# HG changeset patch # User duke # Date 1499281990 -7200 # Node ID 2dc4c11fe48831854916d53c3913bdb7d49023ea # Parent 267e4160fbe27a5b14f1c889588e1ad653d28b91# Parent 3c05feabae497e78c7361201f20c813a10fe54bd Merge diff -r 3c05feabae49 -r 2dc4c11fe488 .hgtags-top-repo --- a/.hgtags-top-repo Wed Jul 05 21:12:06 2017 +0200 +++ b/.hgtags-top-repo Wed Jul 05 21:13:10 2017 +0200 @@ -343,3 +343,4 @@ 48987460c7d49a29013963ee44d090194396bb61 jdk-9+98 7c0577bea4c65d69c5bef67023a89d2efa4fb2f7 jdk-9+99 c1f30ac14db0eaff398429c04cd9fab92e1b4b2a jdk-9+100 +c4d72a1620835b5d657b7b6792c2879367d0154f jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 common/autoconf/basics.m4 --- a/common/autoconf/basics.m4 Wed Jul 05 21:12:06 2017 +0200 +++ b/common/autoconf/basics.m4 Wed Jul 05 21:13:10 2017 +0200 @@ -23,6 +23,74 @@ # questions. # +# Create a function/macro that takes a series of named arguments. The call is +# similar to AC_DEFUN, but the setup of the function looks like this: +# BASIC_DEFUN_NAMED([MYFUNC], [FOO *BAR], [$@], [ +# ... do something +# AC_MSG_NOTICE([Value of BAR is ARG_BAR]) +# ]) +# A star (*) in front of a named argument means that it is required and it's +# presence will be verified. To pass e.g. the first value as a normal indexed +# argument, use [m4_shift($@)] as the third argument instead of [$@]. These +# arguments are referenced in the function by their name prefixed by ARG_, e.g. +# "ARG_FOO". +# +# The generated function can be called like this: +# MYFUNC(FOO: [foo-val], BAR: +# [ +# $ECHO hello world +# ]) +# +# +# Argument 1: Name of the function to define +# Argument 2: List of legal named arguments, with a * prefix for required arguments +# Argument 3: Argument array to treat as named, typically $@ +# Argument 4: The main function body +AC_DEFUN([BASIC_DEFUN_NAMED], +[ + AC_DEFUN($1, [ + m4_foreach(arg, m4_split($2), [ + m4_if(m4_bregexp(arg, [^\*]), -1, + [ + m4_set_add(legal_named_args, arg) + ], + [ + m4_set_add(legal_named_args, m4_substr(arg, 1)) + m4_set_add(required_named_args, m4_substr(arg, 1)) + ] + ) + ]) + + m4_foreach([arg], [$3], [ + m4_define(arg_name, m4_substr(arg, 0, m4_bregexp(arg, [: ]))) + m4_set_contains(legal_named_args, arg_name, [],[AC_MSG_ERROR([Internal error: arg_name is not a valid named argument to [$1]. Valid arguments are 'm4_set_contents(legal_named_args, [ ])'.])]) + m4_set_remove(required_named_args, arg_name) + m4_set_remove(legal_named_args, arg_name) + m4_pushdef([ARG_][]arg_name, m4_substr(arg, m4_incr(m4_incr(m4_bregexp(arg, [: ]))))) + m4_set_add(defined_args, arg_name) + m4_undefine([arg_name]) + ]) + m4_set_empty(required_named_args, [], [ + AC_MSG_ERROR([Internal error: Required named arguments are missing for [$1]. Missing arguments: 'm4_set_contents(required_named_args, [ ])']) + ]) + m4_foreach([arg], m4_indir([m4_dquote]m4_set_listc([legal_named_args])), [ + m4_pushdef([ARG_][]arg, []) + m4_set_add(defined_args, arg) + ]) + m4_set_delete(legal_named_args) + m4_set_delete(required_named_args) + + # Execute function body + $4 + + m4_foreach([arg], m4_indir([m4_dquote]m4_set_listc([defined_args])), [ + m4_popdef([ARG_][]arg) + ]) + + m4_set_delete(defined_args) + ]) +]) + # Test if $1 is a valid argument to $3 (often is $JAVA passed as $3) # If so, then append $1 to $2 \ # Also set JVM_ARG_OK to true/false depending on outcome. @@ -1122,7 +1190,6 @@ # Move configure.log from current directory to the build output root if test -e ./configure.log; then - echo found it $MV -f ./configure.log "$OUTPUT_ROOT/configure.log" 2> /dev/null fi diff -r 3c05feabae49 -r 2dc4c11fe488 common/autoconf/flags.m4 --- a/common/autoconf/flags.m4 Wed Jul 05 21:12:06 2017 +0200 +++ b/common/autoconf/flags.m4 Wed Jul 05 21:13:10 2017 +0200 @@ -425,7 +425,7 @@ # Add runtime stack smashing and undefined behavior checks. # Not all versions of gcc support -fstack-protector STACK_PROTECTOR_CFLAG="-fstack-protector-all" - FLAGS_COMPILER_CHECK_ARGUMENTS([$STACK_PROTECTOR_CFLAG], [], [STACK_PROTECTOR_CFLAG=""]) + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$STACK_PROTECTOR_CFLAG], IF_FALSE: [STACK_PROTECTOR_CFLAG=""]) CFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" CXXFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" @@ -742,7 +742,7 @@ -I${JDK_TOPDIR}/src/java.base/share/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS/native/include \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/include \ - -I${JDK_TOPDIR}/src/java.base/share/native/libjava \ + -I${JDK_TOPDIR}/src/java.base/share/native/libjava \ -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava" # The shared libraries are compiled using the picflag. @@ -896,17 +896,18 @@ AC_SUBST(LDFLAGS_TESTEXE) ]) -# FLAGS_COMPILER_CHECK_ARGUMENTS([ARGUMENT], [RUN-IF-TRUE], -# [RUN-IF-FALSE]) +# FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [ARGUMENT], IF_TRUE: [RUN-IF-TRUE], +# IF_FALSE: [RUN-IF-FALSE]) # ------------------------------------------------------------ # Check that the c and c++ compilers support an argument -AC_DEFUN([FLAGS_COMPILER_CHECK_ARGUMENTS], +BASIC_DEFUN_NAMED([FLAGS_COMPILER_CHECK_ARGUMENTS], + [*ARGUMENT IF_TRUE IF_FALSE], [$@], [ - AC_MSG_CHECKING([if compiler supports "$1"]) + AC_MSG_CHECKING([if compiler supports "ARG_ARGUMENT"]) supports=yes saved_cflags="$CFLAGS" - CFLAGS="$CFLAGS $1" + CFLAGS="$CFLAGS ARG_ARGUMENT" AC_LANG_PUSH([C]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int i;]])], [], [supports=no]) @@ -914,7 +915,7 @@ CFLAGS="$saved_cflags" saved_cxxflags="$CXXFLAGS" - CXXFLAGS="$CXXFLAG $1" + CXXFLAGS="$CXXFLAG ARG_ARGUMENT" AC_LANG_PUSH([C++]) AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int i;]])], [], [supports=no]) @@ -923,23 +924,26 @@ AC_MSG_RESULT([$supports]) if test "x$supports" = "xyes" ; then - m4_ifval([$2], [$2], [:]) + : + ARG_IF_TRUE else - m4_ifval([$3], [$3], [:]) + : + ARG_IF_FALSE fi ]) -# FLAGS_LINKER_CHECK_ARGUMENTS([ARGUMENT], [RUN-IF-TRUE], -# [RUN-IF-FALSE]) +# FLAGS_LINKER_CHECK_ARGUMENTS(ARGUMENT: [ARGUMENT], IF_TRUE: [RUN-IF-TRUE], +# IF_FALSE: [RUN-IF-FALSE]) # ------------------------------------------------------------ # Check that the linker support an argument -AC_DEFUN([FLAGS_LINKER_CHECK_ARGUMENTS], +BASIC_DEFUN_NAMED([FLAGS_LINKER_CHECK_ARGUMENTS], + [*ARGUMENT IF_TRUE IF_FALSE], [$@], [ - AC_MSG_CHECKING([if linker supports "$1"]) + AC_MSG_CHECKING([if linker supports "ARG_ARGUMENT"]) supports=yes saved_ldflags="$LDFLAGS" - LDFLAGS="$LDFLAGS $1" + LDFLAGS="$LDFLAGS ARG_ARGUMENT" AC_LANG_PUSH([C]) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])], [], [supports=no]) @@ -948,9 +952,11 @@ AC_MSG_RESULT([$supports]) if test "x$supports" = "xyes" ; then - m4_ifval([$2], [$2], [:]) + : + ARG_IF_TRUE else - m4_ifval([$3], [$3], [:]) + : + ARG_IF_FALSE fi ]) @@ -965,14 +971,14 @@ *) ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" esac - FLAGS_COMPILER_CHECK_ARGUMENTS([$ZERO_ARCHFLAG], [], [ZERO_ARCHFLAG=""]) + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$ZERO_ARCHFLAG], IF_FALSE: [ZERO_ARCHFLAG=""]) AC_SUBST(ZERO_ARCHFLAG) # Check that the compiler supports -mX (or -qX on AIX) flags # Set COMPILER_SUPPORTS_TARGET_BITS_FLAG to 'true' if it does - FLAGS_COMPILER_CHECK_ARGUMENTS([${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}], - [COMPILER_SUPPORTS_TARGET_BITS_FLAG=true], - [COMPILER_SUPPORTS_TARGET_BITS_FLAG=false]) + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}], + IF_TRUE: [COMPILER_SUPPORTS_TARGET_BITS_FLAG=true], + IF_FALSE: [COMPILER_SUPPORTS_TARGET_BITS_FLAG=false]) AC_SUBST(COMPILER_SUPPORTS_TARGET_BITS_FLAG) AC_ARG_ENABLE([warnings-as-errors], [AS_HELP_STRING([--disable-warnings-as-errors], @@ -1013,9 +1019,9 @@ ;; gcc) # Prior to gcc 4.4, a -Wno-X where X is unknown for that version of gcc will cause an error - FLAGS_COMPILER_CHECK_ARGUMENTS([-Wno-this-is-a-warning-that-do-not-exist], - [GCC_CAN_DISABLE_WARNINGS=true], - [GCC_CAN_DISABLE_WARNINGS=false] + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [-Wno-this-is-a-warning-that-do-not-exist], + IF_TRUE: [GCC_CAN_DISABLE_WARNINGS=true], + IF_FALSE: [GCC_CAN_DISABLE_WARNINGS=false] ) if test "x$GCC_CAN_DISABLE_WARNINGS" = "xtrue"; then DISABLE_WARNING_PREFIX="-Wno-" @@ -1026,9 +1032,9 @@ # Repeate the check for the BUILD_CC CC_OLD="$CC" CC="$BUILD_CC" - FLAGS_COMPILER_CHECK_ARGUMENTS([-Wno-this-is-a-warning-that-do-not-exist], - [BUILD_CC_CAN_DISABLE_WARNINGS=true], - [BUILD_CC_CAN_DISABLE_WARNINGS=false] + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [-Wno-this-is-a-warning-that-do-not-exist], + IF_TRUE: [BUILD_CC_CAN_DISABLE_WARNINGS=true], + IF_FALSE: [BUILD_CC_CAN_DISABLE_WARNINGS=false] ) if test "x$BUILD_CC_CAN_DISABLE_WARNINGS" = "xtrue"; then BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-" diff -r 3c05feabae49 -r 2dc4c11fe488 common/autoconf/generated-configure.sh --- a/common/autoconf/generated-configure.sh Wed Jul 05 21:12:06 2017 +0200 +++ b/common/autoconf/generated-configure.sh Wed Jul 05 21:13:10 2017 +0200 @@ -3451,6 +3451,31 @@ # questions. # +# Create a function/macro that takes a series of named arguments. The call is +# similar to AC_DEFUN, but the setup of the function looks like this: +# BASIC_DEFUN_NAMED([MYFUNC], [FOO *BAR], [$@], [ +# ... do something +# AC_MSG_NOTICE([Value of BAR is ARG_BAR]) +# ]) +# A star (*) in front of a named argument means that it is required and it's +# presence will be verified. To pass e.g. the first value as a normal indexed +# argument, use [m4_shift($@)] as the third argument instead of [$@]. These +# arguments are referenced in the function by their name prefixed by ARG_, e.g. +# "ARG_FOO". +# +# The generated function can be called like this: +# MYFUNC(FOO: [foo-val], BAR: +# [ +# $ECHO hello world +# ]) +# +# +# Argument 1: Name of the function to define +# Argument 2: List of legal named arguments, with a * prefix for required arguments +# Argument 3: Argument array to treat as named, typically $@ +# Argument 4: The main function body + + # Test if $1 is a valid argument to $3 (often is $JAVA passed as $3) # If so, then append $1 to $2 \ # Also set JVM_ARG_OK to true/false depending on outcome. @@ -3886,20 +3911,24 @@ -# FLAGS_COMPILER_CHECK_ARGUMENTS([ARGUMENT], [RUN-IF-TRUE], -# [RUN-IF-FALSE]) +# FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [ARGUMENT], IF_TRUE: [RUN-IF-TRUE], +# IF_FALSE: [RUN-IF-FALSE]) # ------------------------------------------------------------ # Check that the c and c++ compilers support an argument -# FLAGS_LINKER_CHECK_ARGUMENTS([ARGUMENT], [RUN-IF-TRUE], -# [RUN-IF-FALSE]) + + +# FLAGS_LINKER_CHECK_ARGUMENTS(ARGUMENT: [ARGUMENT], IF_TRUE: [RUN-IF-TRUE], +# IF_FALSE: [RUN-IF-FALSE]) # ------------------------------------------------------------ # Check that the linker support an argument + + # # Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4810,7 +4839,7 @@ #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1452261921 +DATE_WHEN_GENERATED=1452780299 ############################################################################### # @@ -45358,6 +45387,54 @@ # "-Og" suppported for GCC 4.8 and later CFLAG_OPTIMIZE_DEBUG_FLAG="-Og" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports \"$CFLAG_OPTIMIZE_DEBUG_FLAG\"" >&5 $as_echo_n "checking if compiler supports \"$CFLAG_OPTIMIZE_DEBUG_FLAG\"... " >&6; } supports=yes @@ -45417,15 +45494,76 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then + : HAS_CFLAG_OPTIMIZE_DEBUG=true else + : HAS_CFLAG_OPTIMIZE_DEBUG=false fi + + + + + + + + + + + # "-z relro" supported in GNU binutils 2.17 and later LINKER_RELRO_FLAG="-Wl,-z,relro" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if linker supports \"$LINKER_RELRO_FLAG\"" >&5 $as_echo_n "checking if linker supports \"$LINKER_RELRO_FLAG\"... " >&6; } supports=yes @@ -45467,15 +45605,76 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then + : HAS_LINKER_RELRO=true else + : HAS_LINKER_RELRO=false fi + + + + + + + + + + + # "-z now" supported in GNU binutils 2.11 and later LINKER_NOW_FLAG="-Wl,-z,now" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if linker supports \"$LINKER_NOW_FLAG\"" >&5 $as_echo_n "checking if linker supports \"$LINKER_NOW_FLAG\"... " >&6; } supports=yes @@ -45517,11 +45716,24 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then + : HAS_LINKER_NOW=true else + : HAS_LINKER_NOW=false fi + + + + + + + + + + + fi # Check for broken SuSE 'ld' for which 'Only anonymous version tag is allowed @@ -46842,6 +47054,49 @@ # Not all versions of gcc support -fstack-protector STACK_PROTECTOR_CFLAG="-fstack-protector-all" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports \"$STACK_PROTECTOR_CFLAG\"" >&5 $as_echo_n "checking if compiler supports \"$STACK_PROTECTOR_CFLAG\"... " >&6; } supports=yes @@ -46902,11 +47157,24 @@ $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then : - else + + else + : STACK_PROTECTOR_CFLAG="" fi + + + + + + + + + + + CFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" CXXFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1" ;; @@ -47384,6 +47652,49 @@ ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports \"$ZERO_ARCHFLAG\"" >&5 $as_echo_n "checking if compiler supports \"$ZERO_ARCHFLAG\"... " >&6; } supports=yes @@ -47444,15 +47755,76 @@ $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then : - else + + else + : ZERO_ARCHFLAG="" fi + + + + + + + + + + + # Check that the compiler supports -mX (or -qX on AIX) flags # Set COMPILER_SUPPORTS_TARGET_BITS_FLAG to 'true' if it does + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports \"${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}\"" >&5 $as_echo_n "checking if compiler supports \"${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}\"... " >&6; } supports=yes @@ -47512,13 +47884,26 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then + : COMPILER_SUPPORTS_TARGET_BITS_FLAG=true else + : COMPILER_SUPPORTS_TARGET_BITS_FLAG=false fi + + + + + + + + + + + # Check whether --enable-warnings-as-errors was given. if test "${enable_warnings_as_errors+set}" = set; then : enableval=$enable_warnings_as_errors; @@ -47565,6 +47950,54 @@ gcc) # Prior to gcc 4.4, a -Wno-X where X is unknown for that version of gcc will cause an error + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports \"-Wno-this-is-a-warning-that-do-not-exist\"" >&5 $as_echo_n "checking if compiler supports \"-Wno-this-is-a-warning-that-do-not-exist\"... " >&6; } supports=yes @@ -47624,12 +48057,25 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then + : GCC_CAN_DISABLE_WARNINGS=true else + : GCC_CAN_DISABLE_WARNINGS=false fi + + + + + + + + + + + if test "x$GCC_CAN_DISABLE_WARNINGS" = "xtrue"; then DISABLE_WARNING_PREFIX="-Wno-" else @@ -47640,6 +48086,54 @@ CC_OLD="$CC" CC="$BUILD_CC" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Execute function body + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports \"-Wno-this-is-a-warning-that-do-not-exist\"" >&5 $as_echo_n "checking if compiler supports \"-Wno-this-is-a-warning-that-do-not-exist\"... " >&6; } supports=yes @@ -47699,12 +48193,25 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then + : BUILD_CC_CAN_DISABLE_WARNINGS=true else + : BUILD_CC_CAN_DISABLE_WARNINGS=false fi + + + + + + + + + + + if test "x$BUILD_CC_CAN_DISABLE_WARNINGS" = "xtrue"; then BUILD_CC_DISABLE_WARNING_PREFIX="-Wno-" else @@ -61523,7 +62030,6 @@ # Move configure.log from current directory to the build output root if test -e ./configure.log; then - echo found it $MV -f ./configure.log "$OUTPUT_ROOT/configure.log" 2> /dev/null fi diff -r 3c05feabae49 -r 2dc4c11fe488 common/autoconf/toolchain.m4 --- a/common/autoconf/toolchain.m4 Wed Jul 05 21:12:06 2017 +0200 +++ b/common/autoconf/toolchain.m4 Wed Jul 05 21:13:10 2017 +0200 @@ -75,8 +75,8 @@ # For full static builds, we're overloading the SHARED_LIBRARY # variables in order to limit the amount of changes required. # It would be better to remove SHARED and just use LIBRARY and - # LIBRARY_SUFFIX for libraries that can be built either - # shared or static and use STATIC_* for libraries that are + # LIBRARY_SUFFIX for libraries that can be built either + # shared or static and use STATIC_* for libraries that are # always built statically. if test "x$STATIC_BUILD" = xtrue; then SHARED_LIBRARY='lib[$]1.a' @@ -824,21 +824,21 @@ # "-Og" suppported for GCC 4.8 and later CFLAG_OPTIMIZE_DEBUG_FLAG="-Og" - FLAGS_COMPILER_CHECK_ARGUMENTS([$CFLAG_OPTIMIZE_DEBUG_FLAG], - [HAS_CFLAG_OPTIMIZE_DEBUG=true], - [HAS_CFLAG_OPTIMIZE_DEBUG=false]) + FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [$CFLAG_OPTIMIZE_DEBUG_FLAG], + IF_TRUE: [HAS_CFLAG_OPTIMIZE_DEBUG=true], + IF_FALSE: [HAS_CFLAG_OPTIMIZE_DEBUG=false]) # "-z relro" supported in GNU binutils 2.17 and later LINKER_RELRO_FLAG="-Wl,-z,relro" - FLAGS_LINKER_CHECK_ARGUMENTS([$LINKER_RELRO_FLAG], - [HAS_LINKER_RELRO=true], - [HAS_LINKER_RELRO=false]) + FLAGS_LINKER_CHECK_ARGUMENTS(ARGUMENT: [$LINKER_RELRO_FLAG], + IF_TRUE: [HAS_LINKER_RELRO=true], + IF_FALSE: [HAS_LINKER_RELRO=false]) # "-z now" supported in GNU binutils 2.11 and later LINKER_NOW_FLAG="-Wl,-z,now" - FLAGS_LINKER_CHECK_ARGUMENTS([$LINKER_NOW_FLAG], - [HAS_LINKER_NOW=true], - [HAS_LINKER_NOW=false]) + FLAGS_LINKER_CHECK_ARGUMENTS(ARGUMENT: [$LINKER_NOW_FLAG], + IF_TRUE: [HAS_LINKER_NOW=true], + IF_FALSE: [HAS_LINKER_NOW=false]) fi # Check for broken SuSE 'ld' for which 'Only anonymous version tag is allowed diff -r 3c05feabae49 -r 2dc4c11fe488 corba/.hgtags --- a/corba/.hgtags Wed Jul 05 21:12:06 2017 +0200 +++ b/corba/.hgtags Wed Jul 05 21:13:10 2017 +0200 @@ -343,3 +343,4 @@ ea285530245cf4e0edf0479121a41347d3030eba jdk-9+98 180212ee1d8710691ba9944593dfc1ff3e4f1532 jdk-9+99 791d0d3ac0138faeb6110bd840a4545bc1950df2 jdk-9+100 +30dfb3bd3d06b4bb80a087babc0d1841edba187b jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 hotspot/.hgtags --- a/hotspot/.hgtags Wed Jul 05 21:12:06 2017 +0200 +++ b/hotspot/.hgtags Wed Jul 05 21:13:10 2017 +0200 @@ -503,3 +503,4 @@ e5b1a23be1e105417ba1c4c576ab373eb3fa2c2b jdk-9+98 f008e8cc10d5b3212fb22d58c96fa01d38654f19 jdk-9+99 bdb0acafc63c42e84d9d8195bf2e2b25ee9c3306 jdk-9+100 +9f45d3d57d6948cf526fbc2e2891a9a74ac6941a jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 hotspot/src/share/vm/prims/nativeLookup.cpp --- a/hotspot/src/share/vm/prims/nativeLookup.cpp Wed Jul 05 21:12:06 2017 +0200 +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ { CC"Java_jdk_internal_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, - { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, + { CC"Java_jdk_internal_perf_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, { CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) }, #if INCLUDE_JVMCI { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", NULL, FN_PTR(JVM_GetJVMCIRuntime) }, diff -r 3c05feabae49 -r 2dc4c11fe488 hotspot/src/share/vm/prims/perf.cpp --- a/hotspot/src/share/vm/prims/perf.cpp Wed Jul 05 21:12:06 2017 +0200 +++ b/hotspot/src/share/vm/prims/perf.cpp Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ #include "runtime/perfMemory.hpp" /* - * Implementation of class sun.misc.Perf + * Implementation of class jdk.internal.perf.Perf */ diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/.hgtags --- a/jaxp/.hgtags Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/.hgtags Wed Jul 05 21:13:10 2017 +0200 @@ -343,3 +343,4 @@ 52b01339235f24c93b679bd6b8fb36a1072ad0ac jdk-9+98 52774b544850c791f1d1c67db2601b33739b18c9 jdk-9+99 d45bcd374f6057851e3c2dcd45607cd362afadfa jdk-9+100 +d3e834ff74e724a2b92a558e18e8cbf81c6dbc59 jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -32,7 +32,6 @@ import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -43,6 +42,7 @@ import static javax.xml.catalog.BaseEntry.CatalogEntryType; import static javax.xml.catalog.CatalogFeatures.DEFER_TRUE; import javax.xml.catalog.CatalogFeatures.Feature; +import static javax.xml.catalog.CatalogMessages.formatMessage; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; @@ -109,25 +109,20 @@ */ public CatalogImpl(CatalogImpl parent, CatalogFeatures f, String... file) throws CatalogException { super(CatalogEntryType.CATALOG); - this.parent = parent; - if (parent == null) { - level = 0; - } else { - level = parent.level + 1; + if (f == null) { + throw new NullPointerException( + formatMessage(CatalogMessages.ERR_NULL_ARGUMENT, new Object[]{"CatalogFeatures"})); } - if (f == null) { - this.features = CatalogFeatures.defaults(); - } else { - this.features = f; + + if (file.length > 0) { + CatalogMessages.reportNPEOnNull("The path to the catalog file", file[0]); } - setPrefer(features.get(Feature.PREFER)); - setDeferred(features.get(Feature.DEFER)); - setResolve(features.get(Feature.RESOLVE)); + + init(parent, f); //Path of catalog files String[] catalogFile = file; - if (level == 0 - && (file == null || (file.length == 0 || file[0] == null))) { + if (level == 0 && file.length == 0) { String files = features.get(Feature.FILES); if (files != null) { catalogFile = files.split(";[ ]*"); @@ -166,6 +161,23 @@ } } + private void init(CatalogImpl parent, CatalogFeatures f) { + this.parent = parent; + if (parent == null) { + level = 0; + } else { + level = parent.level + 1; + } + if (f == null) { + this.features = CatalogFeatures.defaults(); + } else { + this.features = f; + } + setPrefer(features.get(Feature.PREFER)); + setDeferred(features.get(Feature.DEFER)); + setResolve(features.get(Feature.RESOLVE)); + } + /** * Resets the Catalog instance to its initial state. */ diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java Wed Jul 05 21:13:10 2017 +0200 @@ -38,33 +38,38 @@ } /** - * Creates a Catalog object using the specified feature settings and path to - * a catalog file. If the features is null, the default features will be used. - * If the path is empty, System property {@code javax.xml.catalog.files} will - * be read to locate the initial list of catalog files. + * Creates a {@code Catalog} object using the specified feature settings and + * path to one or more catalog files. *

- * If more than one catalog files are specified through the path argument or + * If {@code paths} is empty, system property {@code javax.xml.catalog.files} + * will be read to locate the initial list of catalog files. + *

+ * If more than one catalog files are specified through the paths argument or * {@code javax.xml.catalog.files} property, the first entry is considered * the main catalog, while others are treated as alternative catalogs after * those referenced by the {@code nextCatalog} elements in the main catalog. + *

+ * As specified in + * + * XML Catalogs, OASIS Standard V1.1, invalid path entries will be ignored. + * No error will be reported. In case all entries are invalid, the resolver + * will return as no mapping is found. * * @param features the catalog features - * @param path path(s) to one or more catalogs. + * @param paths path(s) to one or more catalogs. * - * @return a catalog instance - * @throws CatalogException If no catalog can be found whether through the - * specified path or the System property {@code javax.xml.catalog.files}, or - * an error occurs while parsing the catalog + * @return an instance of a {@code Catalog} + * @throws CatalogException If an error occurs while parsing the catalog */ - public static Catalog catalog(CatalogFeatures features, String... path) { - return new CatalogImpl(features, path); + public static Catalog catalog(CatalogFeatures features, String... paths) { + return new CatalogImpl(features, paths); } /** - * Creates an instance of a CatalogResolver using the specified catalog. + * Creates an instance of a {@code CatalogResolver} using the specified catalog. * * @param catalog the catalog instance - * @return an instance of a CatalogResolver + * @return an instance of a {@code CatalogResolver} */ public static CatalogResolver catalogResolver(Catalog catalog) { if (catalog == null) CatalogMessages.reportNPEOnNull("catalog", null); @@ -72,10 +77,10 @@ } /** - * Creates an instance of a CatalogUriResolver using the specified catalog. + * Creates an instance of a {@code CatalogUriResolver} using the specified catalog. * * @param catalog the catalog instance - * @return an instance of a CatalogResolver + * @return an instance of a {@code CatalogResolver} */ public static CatalogUriResolver catalogUriResolver(Catalog catalog) { if (catalog == null) CatalogMessages.reportNPEOnNull("catalog", null); @@ -83,50 +88,60 @@ } /** - * Creates an instance of a CatalogResolver using the specified feature settings - * and path to a catalog file. If the features is null, the default features will - * be used. If the path is empty, System property {@code javax.xml.catalog.files} + * Creates an instance of a {@code CatalogResolver} using the specified feature + * settings and path to one or more catalog files. + *

+ * If {@code paths} is empty, system property {@code javax.xml.catalog.files} * will be read to locate the initial list of catalog files. *

- * If more than one catalog files are specified through the path argument or + * If more than one catalog files are specified through the paths argument or * {@code javax.xml.catalog.files} property, the first entry is considered * the main catalog, while others are treated as alternative catalogs after * those referenced by the {@code nextCatalog} elements in the main catalog. + *

+ * As specified in + * + * XML Catalogs, OASIS Standard V1.1, invalid path entries will be ignored. + * No error will be reported. In case all entries are invalid, the resolver + * will return as no mapping is found. * * @param features the catalog features - * @param path the path(s) to one or more catalogs + * @param paths the path(s) to one or more catalogs * - * @return an instance of a CatalogResolver - * @throws CatalogException If no catalog can be found whether through the - * specified path or the System property {@code javax.xml.catalog.files}, or - * an error occurs while parsing the catalog + * @return an instance of a {@code CatalogResolver} + * @throws CatalogException If an error occurs while parsing the catalog */ - public static CatalogResolver catalogResolver(CatalogFeatures features, String... path) { - Catalog catalog = catalog(features, path); + public static CatalogResolver catalogResolver(CatalogFeatures features, String... paths) { + Catalog catalog = catalog(features, paths); return new CatalogResolverImpl(catalog); } /** - * Creates an instance of a CatalogUriResolver using the specified feature settings - * and path to a catalog file. If the features is null, the default features will - * be used. If the path is empty, System property {@code javax.xml.catalog.files} + * Creates an instance of a {@code CatalogUriResolver} using the specified + * feature settings and path to one or more catalog files. + *

+ * If {@code paths} is empty, system property {@code javax.xml.catalog.files} * will be read to locate the initial list of catalog files. *

- * If more than one catalog files are specified through the path argument or + * If more than one catalog files are specified through the paths argument or * {@code javax.xml.catalog.files} property, the first entry is considered * the main catalog, while others are treated as alternative catalogs after * those referenced by the {@code nextCatalog} elements in the main catalog. + *

+ * As specified in + * + * XML Catalogs, OASIS Standard V1.1, invalid path entries will be ignored. + * No error will be reported. In case all entries are invalid, the resolver + * will return as no mapping is found. * * @param features the catalog features - * @param path the path(s) to one or more catalogs + * @param paths the path(s) to one or more catalogs * - * @return an instance of a CatalogResolver - * @throws CatalogException If no catalog can be found whether through the - * specified path or the System property {@code javax.xml.catalog.files}, or - * an error occurs while parsing the catalog + * @return an instance of a {@code CatalogUriResolver} + * @throws CatalogException If an error occurs while parsing the catalog */ - public static CatalogUriResolver catalogUriResolver(CatalogFeatures features, String... path) { - Catalog catalog = catalog(features, path); + public static CatalogUriResolver catalogUriResolver(CatalogFeatures features, String... paths) { + Catalog catalog = catalog(features, paths); return new CatalogUriResolverImpl(catalog); } } diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java Wed Jul 05 21:13:10 2017 +0200 @@ -43,9 +43,9 @@ * absolute if the absolute URI is required * * @return a {@link javax.xml.transform.Source} object if a mapping is found. - * If no mapping is found, returns a {@link javax.xml.transform.Source} object - * containing an empty {@link java.io.Reader} if the - * {@code javax.xml.catalog.resolve} property is set to {@code ignore}; + * If no mapping is found, returns an empty {@link javax.xml.transform.Source} + * object if the {@code javax.xml.catalog.resolve} property is set to + * {@code ignore}; * returns a {@link javax.xml.transform.Source} object with the original URI * (href, or href resolved with base if base is not null) if the * {@code javax.xml.catalog.resolve} property is set to {@code continue}. diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,6 +72,7 @@ public String getSystemIdStartString () { return systemIdStartString; } + /** * Get the rewritePrefix attribute. * @return The rewritePrefix attribute value. @@ -80,7 +81,6 @@ return rewritePrefix; } - /** * Try to match the specified systemId with the entry. Return the match if it * is successful and the length of the systemIdStartString is longer than the @@ -91,14 +91,20 @@ * @return The replacement URI if the match is successful, null if not. */ public String match(String systemId, int currentMatch) { - if (systemIdStartString.length() <= systemId.length() && + if (systemIdStartString.length() < systemId.length() && systemIdStartString.equals(systemId.substring(0, systemIdStartString.length()))) { if (currentMatch < systemIdStartString.length()) { String prefix = rewritePrefix.toExternalForm(); - if (!prefix.endsWith(SLASH) && !systemId.startsWith(SLASH)) { - return prefix + SLASH + systemId.substring(systemIdStartString.length()); + String sysId; + if (systemIdStartString.endsWith(SLASH)) { + sysId = systemId.substring(systemIdStartString.length()); } else { - return prefix + systemId.substring(systemIdStartString.length()); + sysId = systemId.substring(systemIdStartString.length() + 1); + } + if (prefix.endsWith(SLASH)) { + return prefix + sysId; + } else { + return prefix + SLASH + sysId; } } } diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,6 +72,7 @@ public String getURIStartString () { return uriStartString; } + /** * Get the rewritePrefix attribute. * @return The rewritePrefix attribute value. @@ -91,14 +92,20 @@ */ @Override public String match(String systemId, int currentMatch) { - if (uriStartString.length() <= systemId.length() && + if (uriStartString.length() < systemId.length() && uriStartString.equals(systemId.substring(0, uriStartString.length()))) { if (currentMatch < uriStartString.length()) { String prefix = rewritePrefix.toExternalForm(); - if (!prefix.endsWith(SLASH) && !systemId.startsWith(SLASH)) { - return prefix + SLASH + systemId.substring(uriStartString.length()); + String sysId; + if (uriStartString.endsWith(SLASH)) { + sysId = systemId.substring(uriStartString.length()); } else { - return prefix + systemId.substring(uriStartString.length()); + sysId = systemId.substring(uriStartString.length() + 1); + } + if (prefix.endsWith(SLASH)) { + return prefix + sysId; + } else { + return prefix + SLASH + sysId; } } } diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,4 +52,17 @@ * if setSystemId was not called. */ public String getSystemId(); + + /** + * Indicates whether the {@code Source} object is empty. Empty means + * that there is no input available from this Source. + * + * @implSpec The default implementation of this method throws + * {@link UnsupportedOperationException}. + * + * @return true if the {@code Source} object is empty, false otherwise + */ + default boolean isEmpty() { + throw new UnsupportedOperationException("The isEmpty method is not supported."); + } } diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,6 +122,7 @@ * * @param systemID Base URL for this DOM tree. */ + @Override public void setSystemId(String systemID) { this.systemID = systemID; } @@ -132,7 +133,25 @@ * * @return Base URL for this DOM tree. */ + @Override public String getSystemId() { return this.systemID; } + + /** + * Indicates whether the {@code DOMSource} object is empty. Empty is + * defined as follows: + *

+ * + * @return true if the {@code DOMSource} object is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return systemID == null && (node == null || !node.hasChildNodes()); + } } diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,6 +147,7 @@ * * @param systemId The system identifier as a URI string. */ + @Override public void setSystemId(String systemId) { if (null == inputSource) { @@ -162,6 +163,7 @@ * * @return Base URL for the Source, or null. */ + @Override public String getSystemId() { if (inputSource == null) { @@ -207,4 +209,22 @@ return null; } } + + /** + * Indicates whether the {@code SAXSource} object is empty. Empty is + * defined as follows: + * + * + * @return true if the {@code SAXSource} object is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return getSystemId() == null && (inputSource == null || inputSource.isEmpty()); + } } diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -209,6 +209,7 @@ * @throws UnsupportedOperationException Is always * thrown by this method. */ + @Override public void setSystemId(final String systemId) { throw new UnsupportedOperationException( @@ -229,8 +230,21 @@ * * @return System identifier used by this StAXSource. */ + @Override public String getSystemId() { return systemId; } + + /** + * Indicates whether the {@code StAXSource} object is empty. Since a + * {@code StAXSource} object can never be empty, this method always returns + * false. + * + * @return unconditionally false + */ + @Override + public boolean isEmpty() { + return false; + } } diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,10 @@ package javax.xml.transform.stream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import javax.xml.transform.Result; import javax.xml.transform.Source; @@ -233,6 +235,7 @@ * * @param systemId The system identifier as a URL string. */ + @Override public void setSystemId(String systemId) { this.systemId = systemId; } @@ -243,6 +246,7 @@ * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ + @Override public String getSystemId() { return systemId; } @@ -259,6 +263,59 @@ this.systemId = f.toURI().toASCIIString(); } + /** + * Indicates whether the {@code StreamSource} object is empty. Empty is + * defined as follows: + * + *

+ * In case of error while checking the byte or character stream, the method + * will return false to allow the XML processor to handle the error. + * + * @return true if the {@code StreamSource} object is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return (publicId == null && systemId == null && isStreamEmpty()); + } + + private boolean isStreamEmpty() { + boolean empty = true; + try { + if (inputStream != null) { + inputStream.reset(); + int bytesRead = inputStream.available(); + if (bytesRead > 0) { + return false; + } + } + + if (reader != null) { + reader.reset(); + int c = reader.read(); + reader.reset(); + if (c != -1) { + return false; + } + } + } catch (IOException ex) { + //in case of error, return false + return false; + } + + return empty; + } + ////////////////////////////////////////////////////////////////////// // Internal state. ////////////////////////////////////////////////////////////////////// diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java --- a/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ package org.xml.sax; +import java.io.IOException; import java.io.Reader; import java.io.InputStream; @@ -343,8 +344,57 @@ return characterStream; } + /** + * Indicates whether the {@code InputSource} object is empty. Empty is + * defined as follows: + *

+ *

+ * In case of error while checking the byte or character stream, the method + * will return false to allow the XML processor to handle the error. + * + * @return true if the {@code InputSource} object is empty, false otherwise + */ + public boolean isEmpty() { + return (publicId == null && systemId == null && isStreamEmpty()); + } + private boolean isStreamEmpty() { + boolean empty = true; + try { + if (byteStream != null) { + byteStream.reset(); + int bytesRead = byteStream.available(); + if (bytesRead > 0) { + return false; + } + } + if (characterStream != null) { + characterStream.reset(); + int c = characterStream.read(); + characterStream.reset(); + if (c != -1) { + return false; + } + } + } catch (IOException ex) { + //in case of error, return false + return false; + } + + return empty; + } //////////////////////////////////////////////////////////////////// // Internal state. //////////////////////////////////////////////////////////////////// diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java --- a/jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -56,23 +56,14 @@ @DataProvider(name = "catalog-countOfLoadedCatalogFile") private Object[][] data() { - return new Object[][] { - // This catalog specifies null catalog explicitly, - // and the count of loaded catalogs should be 0. - { createCatalog(null), 0 }, - - // This catalog specifies null catalog implicitly, - // and the count of loaded catalogs should be 0. - { createCatalog(CatalogFeatures.defaults()), 0 }, - - // This catalog loads null catalog with true DEFER, - // and the count of loaded catalogs should be 0. - { createCatalog(createDeferFeature(DEFER_TRUE)), 0 }, - - // This catalog loads null catalog with false DEFER. - // It should load all of none-current catalogs and the - // count of loaded catalogs should be 3. - { createCatalog(createDeferFeature(DEFER_FALSE)), 3 } }; + return new Object[][]{ + // By default, alternative catalogs are not loaded. + {createCatalog(CatalogFeatures.defaults()), 0}, + // Alternative catalogs are not loaded when DEFER is set to true. + {createCatalog(createDeferFeature(DEFER_TRUE)), 0}, + // The 3 alternative catalogs are not pre-loaded + //when DEFER is set to false. + {createCatalog(createDeferFeature(DEFER_FALSE)), 3}}; } private CatalogFeatures createDeferFeature(String defer) { diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java --- a/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java Wed Jul 05 21:13:10 2017 +0200 @@ -83,7 +83,7 @@ * Creates CatalogResolver with a set of catalogs. */ static CatalogResolver catalogResolver(String... catalogName) { - return catalogResolver(null, catalogName); + return catalogResolver(CatalogFeatures.defaults(), catalogName); } /* @@ -91,15 +91,16 @@ */ static CatalogResolver catalogResolver(CatalogFeatures features, String... catalogName) { - return CatalogManager.catalogResolver(features, - getCatalogPaths(catalogName)); + return (catalogName == null) ? + CatalogManager.catalogResolver(features) : + CatalogManager.catalogResolver(features, getCatalogPaths(catalogName)); } /* * Creates catalogUriResolver with a set of catalogs. */ static CatalogUriResolver catalogUriResolver(String... catalogName) { - return catalogUriResolver(null, catalogName); + return catalogUriResolver(CatalogFeatures.defaults(), catalogName); } /* @@ -107,8 +108,9 @@ */ static CatalogUriResolver catalogUriResolver( CatalogFeatures features, String... catalogName) { - return CatalogManager.catalogUriResolver(features, - getCatalogPaths(catalogName)); + return (catalogName == null) ? + CatalogManager.catalogUriResolver(features) : + CatalogManager.catalogUriResolver(features, getCatalogPaths(catalogName)); } // Gets the paths of the specified catalogs. diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/test/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java --- a/jaxp/test/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java Wed Jul 05 21:13:10 2017 +0200 @@ -89,7 +89,7 @@ /** * BOM table for storing BOM header. */ - private final static Map bom = new HashMap(); + private final static Map bom = new HashMap<>(); /** * Initialize all BOM headers. diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import javax.xml.catalog.CatalogFeatures.Feature; import javax.xml.catalog.CatalogManager; import javax.xml.catalog.CatalogResolver; +import javax.xml.catalog.CatalogUriResolver; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import static jaxp.library.JAXPTestUtilities.getPathByClassName; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import org.w3c.dom.Element; import org.xml.sax.Attributes; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; @@ -42,12 +41,66 @@ import org.xml.sax.ext.DefaultHandler2; /* - * @bug 8081248 + * @bug 8081248, 8144966, 8146606 * @summary Tests basic Catalog functions. */ public class CatalogTest { /* + @bug 8146606 + Verifies that the resulting systemId does not contain duplicate slashes + */ + public void testRewriteSystem() { + String catalog = getClass().getResource("rewriteCatalog.xml").getFile(); + + try { + CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); + String actualSystemId = resolver.resolveEntity(null, "http://remote.com/dtd/book.dtd").getSystemId(); + Assert.assertTrue(!actualSystemId.contains("//"), "result contains duplicate slashes"); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + + } + + /* + @bug 8146606 + Verifies that the resulting systemId does not contain duplicate slashes + */ + public void testRewriteUri() { + String catalog = getClass().getResource("rewriteCatalog.xml").getFile(); + + try { + + CatalogUriResolver resolver = CatalogManager.catalogUriResolver(CatalogFeatures.defaults(), catalog); + String actualSystemId = resolver.resolve("http://remote.com/import/import.xsl", null).getSystemId(); + Assert.assertTrue(!actualSystemId.contains("//"), "result contains duplicate slashes"); + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + + /* + @bug 8144966 + Verifies that passing null as CatalogFeatures will result in a NPE. + */ + @Test(expectedExceptions = NullPointerException.class) + public void testFeatureNull() { + CatalogResolver resolver = CatalogManager.catalogResolver(null, ""); + + } + + /* + @bug 8144966 + Verifies that passing null as the path will result in a NPE. + */ + @Test(expectedExceptions = NullPointerException.class) + public void testPathNull() { + String path = null; + CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), path); + } + + /* Tests basic catalog feature by using a CatalogResolver instance to resolve a DTD reference to a locally specified DTD file. If the resolution is successful, the Handler shall return the value of the entity reference @@ -61,7 +114,7 @@ } String url = getClass().getResource(xml).getFile(); try { - CatalogResolver cr = CatalogManager.catalogResolver(null, catalog); + CatalogResolver cr = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); XMLReader reader = saxParser.getXMLReader(); reader.setEntityResolver(cr); MyHandler handler = new MyHandler(saxParser); @@ -84,7 +137,7 @@ String test = "testInvalidCatalog"; try { - CatalogResolver resolver = CatalogManager.catalogResolver(null, catalog); + CatalogResolver resolver = CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalog); String actualSystemId = resolver.resolveEntity(null, "http://remote/xml/dtd/sys/alice/docAlice.dtd").getSystemId(); } catch (Exception e) { String msg = e.getMessage(); diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteCatalog.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteCatalog.xml Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,11 @@ + + + + + + + + + diff -r 3c05feabae49 -r 2dc4c11fe488 jaxp/test/javax/xml/jaxp/unittest/common/Sources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/common/Sources.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package common; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamSource; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/* + * @bug 8144967 + * @summary Tests related to the javax.xml.transform.Source + * and org.xml.sax.InputSource + */ +public class Sources { + + /** + * @bug 8144967 + * Tests whether a Source object is empty + * @param source the Source object + */ + @Test(dataProvider = "emptySources") + public void testIsEmpty(Source source) { + Assert.assertTrue(source.isEmpty(), "The source is not empty"); + } + + /** + * @bug 8144967 + * Tests that the source is not empty + * @param source the Source object + */ + @Test(dataProvider = "nonEmptySources") + public void testIsNotEmpty(Source source) { + Assert.assertTrue(!source.isEmpty(), "The source is empty"); + } + + /** + * @bug 8144967 + * Tests whether an InputSource object is empty + * @param source the InputSource object + */ + @Test(dataProvider = "emptyInputSource") + public void testISIsEmpty(InputSource source) { + Assert.assertTrue(source.isEmpty(), "The source is not empty"); + } + + /* + * DataProvider: sources that are empty + */ + @DataProvider(name = "emptySources") + Object[][] getSources() throws URISyntaxException { + + return new Object[][]{ + {new DOMSource()}, + {new DOMSource(getDocument())}, + {new SAXSource()}, + {new SAXSource(new InputSource(new StringReader("")))}, + {new SAXSource(getXMLReader(), new InputSource(new StringReader("")))}, + {new StreamSource()}, + {new StreamSource(new ByteArrayInputStream("".getBytes()))}, + {new StreamSource(new StringReader(""))}, + {new StreamSource(new StringReader(""), null)}, + {new StreamSource((String) null)} + }; + } + + /* + * DataProvider: sources that are not empty + */ + @DataProvider(name = "nonEmptySources") + Object[][] getSourcesEx() throws URISyntaxException { + StAXSource ss = null; + try { + ss = new StAXSource(getXMLEventReader()); + } catch (XMLStreamException ex) {} + + return new Object[][]{ + //This will set a non-null systemId on the resulting StreamSource + {new StreamSource(new File(""))}, + //Can't tell because XMLStreamReader is a pull parser, cursor advancement + //would have been required in order to examine the reader. + {new StAXSource(getXMLStreamReader())}, + {ss} + }; + } + + /* + * DataProvider: sources that are empty + */ + @DataProvider(name = "emptyInputSource") + Object[][] getInputSources() throws URISyntaxException { + byte[] utf8Bytes = null; + try { + utf8Bytes = "".getBytes("UTF8"); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException(ex.getMessage()); + } + return new Object[][]{ + {new InputSource()}, + {new InputSource(new ByteArrayInputStream(utf8Bytes))}, + {new InputSource(new StringReader(""))}, + {new InputSource((String) null)} + }; + } + + /** + * Returns an instance of Document. + * + * @return an instance of Document. + */ + private Document getDocument() { + Document doc = null; + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + doc = dbf.newDocumentBuilder().newDocument(); + } catch (ParserConfigurationException ex) {} + return doc; + } + + /** + * Returns an instance of XMLReader. + * + * @return an instance of XMLReader. + */ + private XMLReader getXMLReader() { + XMLReader reader = null; + try { + reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); + } catch (ParserConfigurationException | SAXException ex) {} + return reader; + } + + /** + * Returns an instance of XMLStreamReader. + * + * @return an instance of XMLStreamReader. + */ + private XMLStreamReader getXMLStreamReader() { + XMLStreamReader r = null; + try { + XMLInputFactory xif = XMLInputFactory.newInstance(); + r = xif.createXMLStreamReader(new ByteArrayInputStream("".getBytes())); + } catch (XMLStreamException ex) {} + + return r; + } + + /** + * Returns an instance of XMLEventReader. + * + * @return an instance of XMLEventReader. + */ + private XMLEventReader getXMLEventReader() { + XMLEventReader r = null; + try { + r = XMLInputFactory.newInstance().createXMLEventReader( + new ByteArrayInputStream("".getBytes())); + } catch (XMLStreamException ex) {} + + return r; + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jaxws/.hgtags --- a/jaxws/.hgtags Wed Jul 05 21:12:06 2017 +0200 +++ b/jaxws/.hgtags Wed Jul 05 21:13:10 2017 +0200 @@ -346,3 +346,4 @@ 67c84077edc3db6b24998b35970b37c01aae985e jdk-9+98 97b31ca0dd77483cf20ff99a033a455673639578 jdk-9+99 d0a97e57d2336238edf6a4cd60aafe67deb7258d jdk-9+100 +3e99318616da903e0dc8f07f9f9203dc1bd49921 jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/.hgtags --- a/jdk/.hgtags Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/.hgtags Wed Jul 05 21:13:10 2017 +0200 @@ -343,3 +343,4 @@ f86ee68d1107dad41a27efc34306e0e56244a12e jdk-9+98 e1a789be1535741274c9779f4d4ca3495196b5c3 jdk-9+99 3d452840f48299a36842760d17c0c8402f0e1266 jdk-9+100 +5e8370fb3ed925335164afe340d1e54beab2d4d5 jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/make/gendata/GendataBreakIterator.gmk --- a/jdk/make/gendata/GendataBreakIterator.gmk Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/make/gendata/GendataBreakIterator.gmk Wed Jul 05 21:13:10 2017 +0200 @@ -48,7 +48,6 @@ $(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := $(TEXT_SRCDIR), \ - INCLUDES := $(TEXT_PKG), \ INCLUDE_FILES := $(TEXT_SOURCES), \ BIN := $(BREAK_ITERATOR_CLASSES))) diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/lang/ClassLoader.java --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Wed Jul 05 21:13:10 2017 +0200 @@ -50,6 +50,8 @@ import java.util.Hashtable; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; + +import jdk.internal.perf.PerfCounter; import sun.misc.Resource; import sun.misc.URLClassPath; import sun.reflect.CallerSensitive; @@ -423,9 +425,9 @@ c = findClass(name); // this is the defining class loader; record the stats - sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); - sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); - sun.misc.PerfCounter.getFindClasses().increment(); + PerfCounter.getParentDelegationTime().addTime(t1 - t0); + PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); + PerfCounter.getFindClasses().increment(); } } if (resolve) { diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java --- a/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java Wed Jul 05 21:13:10 2017 +0200 @@ -61,6 +61,9 @@ * local variable array is an {@link PrimitiveValue} object; * otherwise, the element is an {@code Object}. * + *

The returned array may contain null entries if a local variable is not + * live. + * * @return the local variable array of this stack frame. */ public Object[] getLocals(); diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/lang/System.java --- a/jdk/src/java.base/share/classes/java/lang/System.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/System.java Wed Jul 05 21:13:10 2017 +0200 @@ -1535,6 +1535,8 @@ * @return an instance of {@link Logger} that can be used by the calling * class. * @throws NullPointerException if {@code name} is {@code null}. + * + * @since 9 */ @CallerSensitive public static Logger getLogger(String name) { @@ -1572,6 +1574,8 @@ * resource bundle for message localization. * @throws NullPointerException if {@code name} is {@code null} or * {@code bundle} is {@code null}. + * + * @since 9 */ @CallerSensitive public static Logger getLogger(String name, ResourceBundle bundle) { diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3120,6 +3120,8 @@ MethodHandle handler) { MethodType ttype = target.type(); MethodType htype = handler.type(); + if (!Throwable.class.isAssignableFrom(exType)) + throw new ClassCastException(exType.getName()); if (htype.parameterCount() < 1 || !htype.parameterType(0).isAssignableFrom(exType)) throw newIllegalArgumentException("handler does not accept exception type "+exType); diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/lang/ref/Cleaner.java --- a/jdk/src/java.base/share/classes/java/lang/ref/Cleaner.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/ref/Cleaner.java Wed Jul 05 21:13:10 2017 +0200 @@ -28,7 +28,7 @@ import java.util.Objects; import java.util.concurrent.ThreadFactory; -import jdk.internal.misc.CleanerImpl; +import jdk.internal.ref.CleanerImpl; /** * {@code Cleaner} manages a set of object references and corresponding cleaning actions. diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/net/SocketImpl.java --- a/jdk/src/java.base/share/classes/java/net/SocketImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/net/SocketImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -376,19 +376,23 @@ * @since 1.9 */ protected void setOption(SocketOption name, T value) throws IOException { - if (name == StandardSocketOptions.SO_KEEPALIVE) { + if (name == StandardSocketOptions.SO_KEEPALIVE && + (getSocket() != null)) { setOption(SocketOptions.SO_KEEPALIVE, value); - } else if (name == StandardSocketOptions.SO_SNDBUF) { + } else if (name == StandardSocketOptions.SO_SNDBUF && + (getSocket() != null)) { setOption(SocketOptions.SO_SNDBUF, value); } else if (name == StandardSocketOptions.SO_RCVBUF) { setOption(SocketOptions.SO_RCVBUF, value); } else if (name == StandardSocketOptions.SO_REUSEADDR) { setOption(SocketOptions.SO_REUSEADDR, value); - } else if (name == StandardSocketOptions.SO_LINGER) { + } else if (name == StandardSocketOptions.SO_LINGER && + (getSocket() != null)) { setOption(SocketOptions.SO_LINGER, value); } else if (name == StandardSocketOptions.IP_TOS) { setOption(SocketOptions.IP_TOS, value); - } else if (name == StandardSocketOptions.TCP_NODELAY) { + } else if (name == StandardSocketOptions.TCP_NODELAY && + (getSocket() != null)) { setOption(SocketOptions.TCP_NODELAY, value); } else { throw new UnsupportedOperationException("unsupported option"); @@ -412,19 +416,23 @@ */ @SuppressWarnings("unchecked") protected T getOption(SocketOption name) throws IOException { - if (name == StandardSocketOptions.SO_KEEPALIVE) { + if (name == StandardSocketOptions.SO_KEEPALIVE && + (getSocket() != null)) { return (T)getOption(SocketOptions.SO_KEEPALIVE); - } else if (name == StandardSocketOptions.SO_SNDBUF) { + } else if (name == StandardSocketOptions.SO_SNDBUF && + (getSocket() != null)) { return (T)getOption(SocketOptions.SO_SNDBUF); } else if (name == StandardSocketOptions.SO_RCVBUF) { return (T)getOption(SocketOptions.SO_RCVBUF); } else if (name == StandardSocketOptions.SO_REUSEADDR) { return (T)getOption(SocketOptions.SO_REUSEADDR); - } else if (name == StandardSocketOptions.SO_LINGER) { + } else if (name == StandardSocketOptions.SO_LINGER && + (getSocket() != null)) { return (T)getOption(SocketOptions.SO_LINGER); } else if (name == StandardSocketOptions.IP_TOS) { return (T)getOption(SocketOptions.IP_TOS); - } else if (name == StandardSocketOptions.TCP_NODELAY) { + } else if (name == StandardSocketOptions.TCP_NODELAY && + (getSocket() != null)) { return (T)getOption(SocketOptions.TCP_NODELAY); } else { throw new UnsupportedOperationException("unsupported option"); diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/net/URI.java --- a/jdk/src/java.base/share/classes/java/net/URI.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/net/URI.java Wed Jul 05 21:13:10 2017 +0200 @@ -1146,13 +1146,30 @@ if (part != null) { return part; } - StringBuilder sb = new StringBuilder(); - appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(), + + String s = string; + if (s != null) { + // if string is defined, components will have been parsed + int start = 0; + int end = s.length(); + if (scheme != null) { + start = scheme.length() + 1; + } + if (fragment != null) { + end -= fragment.length() + 1; + } + if (path != null && path.length() == end - start) { + part = path; + } else { + part = s.substring(start, end); + } + } else { + StringBuilder sb = new StringBuilder(); + appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(), host, port, getPath(), getQuery()); - if (sb.length() == 0) { - return null; + part = sb.toString(); } - return schemeSpecificPart = sb.toString(); + return schemeSpecificPart = part; } /** @@ -3056,7 +3073,6 @@ // void parse(boolean rsa) throws URISyntaxException { requireServerAuthority = rsa; - int ssp; // Start of scheme-specific part int n = input.length(); int p = scan(0, n, "/?#", ":"); if ((p >= 0) && at(p, n, ':')) { @@ -3066,21 +3082,20 @@ checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name"); scheme = input.substring(0, p); p++; // Skip ':' - ssp = p; if (at(p, n, '/')) { p = parseHierarchical(p, n); } else { + // opaque; need to create the schemeSpecificPart int q = scan(p, n, "#"); if (q <= p) failExpecting("scheme-specific part", p); checkChars(p, q, L_URIC, H_URIC, "opaque part"); + schemeSpecificPart = input.substring(p, q); p = q; } } else { - ssp = 0; p = parseHierarchical(0, n); } - schemeSpecificPart = input.substring(ssp, p); if (at(p, n, '#')) { checkChars(p + 1, n, L_URIC, H_URIC, "fragment"); fragment = input.substring(p + 1, n); diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/net/URLClassLoader.java --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java Wed Jul 05 21:13:10 2017 +0200 @@ -52,6 +52,7 @@ import jdk.internal.misc.JavaNetAccess; import jdk.internal.misc.SharedSecrets; +import jdk.internal.perf.PerfCounter; import sun.misc.Resource; import sun.misc.URLClassPath; import sun.net.www.ParseUtil; @@ -459,14 +460,14 @@ // Use (direct) ByteBuffer: CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); - sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); + PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); return defineClass(name, bb, cs); } else { byte[] b = res.getBytes(); // must read certificates AFTER reading bytes. CodeSigner[] signers = res.getCodeSigners(); CodeSource cs = new CodeSource(url, signers); - sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); + PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0); return defineClass(name, b, 0, b.length, cs); } } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/security/ProtectionDomain.java --- a/jdk/src/java.base/share/classes/java/security/ProtectionDomain.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/security/ProtectionDomain.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +27,12 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; -import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import jdk.internal.misc.JavaSecurityAccess; import jdk.internal.misc.JavaSecurityProtectionDomainAccess; @@ -472,11 +472,15 @@ * * This class stores ProtectionDomains as weak keys in a ConcurrentHashMap * with additional support for checking and removing weak keys that are no - * longer in use. + * longer in use. There can be cases where the permission collection may + * have a chain of strong references back to the ProtectionDomain, which + * ordinarily would prevent the entry from being removed from the map. To + * address that, we wrap the permission collection in a SoftReference so + * that it can be reclaimed by the garbage collector due to memory demand. */ private static class PDCache implements ProtectionDomainCache { private final ConcurrentHashMap + SoftReference> pdMap = new ConcurrentHashMap<>(); private final ReferenceQueue queue = new ReferenceQueue<>(); @@ -485,15 +489,15 @@ processQueue(queue, pdMap); WeakProtectionDomainKey weakPd = new WeakProtectionDomainKey(pd, queue); - pdMap.putIfAbsent(weakPd, pc); + pdMap.put(weakPd, new SoftReference<>(pc)); } @Override public PermissionCollection get(ProtectionDomain pd) { processQueue(queue, pdMap); - WeakProtectionDomainKey weakPd = - new WeakProtectionDomainKey(pd, queue); - return pdMap.get(weakPd); + WeakProtectionDomainKey weakPd = new WeakProtectionDomainKey(pd); + SoftReference sr = pdMap.get(weakPd); + return (sr == null) ? null : sr.get(); } /** @@ -533,11 +537,20 @@ this((pd == null ? NULL_KEY : pd.key), rq); } + WeakProtectionDomainKey(ProtectionDomain pd) { + this(pd == null ? NULL_KEY : pd.key); + } + private WeakProtectionDomainKey(Key key, ReferenceQueue rq) { super(key, rq); hash = key.hashCode(); } + private WeakProtectionDomainKey(Key key) { + super(key); + hash = key.hashCode(); + } + /** * Returns the identity hash code of the original referent. */ diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/time/LocalDate.java --- a/jdk/src/java.base/share/classes/java/time/LocalDate.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/time/LocalDate.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1369,6 +1369,23 @@ if (daysToAdd == 0) { return this; } + long dom = day + daysToAdd; + if (dom > 0) { + if (dom <= 28) { + return new LocalDate(year, month, (int) dom); + } else if (dom <= 59) { // 59th Jan is 28th Feb, 59th Feb is 31st Mar + long monthLen = lengthOfMonth(); + if (dom <= monthLen) { + return new LocalDate(year, month, (int) dom); + } else if (month < 12) { + return new LocalDate(year, month + 1, (int) (dom - monthLen)); + } else { + YEAR.checkValidValue(year + 1); + return new LocalDate(year + 1, 1, (int) (dom - monthLen)); + } + } + } + long mjDay = Math.addExact(toEpochDay(), daysToAdd); return LocalDate.ofEpochDay(mjDay); } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/util/Locale.java --- a/jdk/src/java.base/share/classes/java/util/Locale.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/util/Locale.java Wed Jul 05 21:13:10 2017 +0200 @@ -3144,6 +3144,18 @@ && range.equals(other.range) && weight == other.weight; } + + /** + * Returns an informative string representation of this {@code LanguageRange} + * object, consisting of language range and weight if the range is + * weighted and the weight is less than the max weight. + * + * @return a string representation of this {@code LanguageRange} object. + */ + @Override + public String toString() { + return (weight == MAX_WEIGHT) ? range : range + ";q=" + weight; + } } /** diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/java/util/zip/ZipFile.java --- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Wed Jul 05 21:13:10 2017 +0200 @@ -54,6 +54,7 @@ import java.util.stream.StreamSupport; import jdk.internal.misc.JavaUtilZipFileAccess; import jdk.internal.misc.SharedSecrets; +import jdk.internal.perf.PerfCounter; import static java.util.zip.ZipConstants.*; import static java.util.zip.ZipConstants64.*; @@ -210,8 +211,8 @@ this.name = name; long t0 = System.nanoTime(); this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0); - sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); - sun.misc.PerfCounter.getZipFileCount().increment(); + PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); + PerfCounter.getZipFileCount().increment(); } /** diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java --- a/jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,788 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.misc; - -import java.lang.ref.Cleaner; -import java.lang.ref.Cleaner.Cleanable; -import java.lang.ref.PhantomReference; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Objects; -import java.util.concurrent.ThreadFactory; -import java.util.function.Function; - -import sun.misc.InnocuousThread; - -/** - * CleanerImpl manages a set of object references and corresponding cleaning actions. - * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}. - */ -public final class CleanerImpl implements Runnable { - - /** - * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. - */ - private static Function cleanerImplAccess = null; - - /** - * Heads of a CleanableList for each reference type. - */ - final PhantomCleanable phantomCleanableList; - - final WeakCleanable weakCleanableList; - - final SoftCleanable softCleanableList; - - // The ReferenceQueue of pending cleaning actions - final ReferenceQueue queue; - - /** - * Called by Cleaner static initialization to provide the function - * to map from Cleaner to CleanerImpl. - * @param access a function to map from Cleaner to CleanerImpl - */ - public static void setCleanerImplAccess(Function access) { - if (cleanerImplAccess == null) { - cleanerImplAccess = access; - } - } - - /** - * Called to get the CleanerImpl for a Cleaner. - * @param cleaner the cleaner - * @return the corresponding CleanerImpl - */ - private static CleanerImpl getCleanerImpl(Cleaner cleaner) { - return cleanerImplAccess.apply(cleaner); - } - - /** - * Constructor for CleanerImpl. - */ - public CleanerImpl() { - queue = new ReferenceQueue<>(); - phantomCleanableList = new PhantomCleanableRef(this); - weakCleanableList = new WeakCleanableRef(this); - softCleanableList = new SoftCleanableRef(this); - } - - /** - * Starts the Cleaner implementation. - * When started waits for Cleanables to be queued. - * @param service the cleaner - * @param threadFactory the thread factory - */ - public void start(Cleaner service, ThreadFactory threadFactory) { - // schedule a nop cleaning action for the service, so the associated thread - // will continue to run at least until the service is reclaimable. - new PhantomCleanableRef(service, service, () -> {}); - - if (threadFactory == null) { - threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); - } - - // now that there's at least one cleaning action, for the service, - // we can start the associated thread, which runs until - // all cleaning actions have been run. - Thread thread = threadFactory.newThread(this); - thread.setDaemon(true); - thread.start(); - } - - /** - * Process queued Cleanables as long as the cleanable lists are not empty. - * A Cleanable is in one of the lists for each Object and for the Cleaner - * itself. - * Terminates when the Cleaner is no longer reachable and - * has been cleaned and there are no more Cleanable instances - * for which the object is reachable. - *

- * If the thread is a ManagedLocalsThread, the threadlocals - * are erased before each cleanup - */ - public void run() { - Thread t = Thread.currentThread(); - InnocuousThread mlThread = (t instanceof InnocuousThread) - ? (InnocuousThread) t - : null; - while (!phantomCleanableList.isListEmpty() || - !weakCleanableList.isListEmpty() || - !softCleanableList.isListEmpty()) { - if (mlThread != null) { - // Clear the thread locals - mlThread.eraseThreadLocals(); - } - try { - // Wait for a Ref, with a timeout to avoid getting hung - // due to a race with clear/clean - Cleanable ref = (Cleanable) queue.remove(60 * 1000L); - if (ref != null) { - ref.clean(); - } - } catch (InterruptedException i) { - continue; // ignore the interruption - } catch (Throwable e) { - // ignore exceptions from the cleanup action - } - } - } - - /** - * PhantomCleanable subclasses efficiently encapsulate cleanup state and - * the cleaning action. - * Subclasses implement the abstract {@link #performCleanup()} method - * to provide the cleaning action. - * When constructed, the object reference and the {@link Cleanable Cleanable} - * are registered with the {@link Cleaner}. - * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the - * referent becomes phantom reachable. - */ - public static abstract class PhantomCleanable extends PhantomReference - implements Cleaner.Cleanable { - - /** - * Links to previous and next in a doubly-linked list. - */ - PhantomCleanable prev = this, next = this; - - /** - * The CleanerImpl for this Cleanable. - */ - private final CleanerImpl cleanerImpl; - - /** - * Constructs new {@code PhantomCleanable} with - * {@code non-null referent} and {@code non-null cleaner}. - * The {@code cleaner} is not retained; it is only used to - * register the newly constructed {@link Cleaner.Cleanable Cleanable}. - * - * @param referent the referent to track - * @param cleaner the {@code Cleaner} to register with - */ - public PhantomCleanable(T referent, Cleaner cleaner) { - super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue); - this.cleanerImpl = getCleanerImpl(cleaner); - insert(); - - // TODO: Replace getClass() with ReachabilityFence when it is available - cleaner.getClass(); - referent.getClass(); - } - - /** - * Construct a new root of the list; not inserted. - */ - PhantomCleanable(CleanerImpl cleanerImpl) { - super(null, null); - this.cleanerImpl = cleanerImpl; - } - - /** - * Insert this PhantomCleanable after the list head. - */ - private void insert() { - final PhantomCleanable list = cleanerImpl.phantomCleanableList; - synchronized (list) { - prev = list; - next = list.next; - next.prev = this; - list.next = this; - } - } - - /** - * Remove this PhantomCleanable from the list. - * - * @return true if Cleanable was removed or false if not because - * it had already been removed before - */ - private boolean remove() { - PhantomCleanable list = cleanerImpl.phantomCleanableList; - synchronized (list) { - if (next != this) { - next.prev = prev; - prev.next = next; - prev = this; - next = this; - return true; - } - return false; - } - } - - /** - * Returns true if the list's next reference refers to itself. - * - * @return true if the list is empty - */ - boolean isListEmpty() { - PhantomCleanable list = cleanerImpl.phantomCleanableList; - synchronized (list) { - return list == list.next; - } - } - - /** - * Unregister this PhantomCleanable and invoke {@link #performCleanup()}, - * ensuring at-most-once semantics. - */ - @Override - public final void clean() { - if (remove()) { - super.clear(); - performCleanup(); - } - } - - /** - * Unregister this PhantomCleanable and clear the reference. - * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. - */ - @Override - public void clear() { - if (remove()) { - super.clear(); - } - } - - /** - * The {@code performCleanup} abstract method is overridden - * to implement the cleaning logic. - * The {@code performCleanup} method should not be called except - * by the {@link #clean} method which ensures at most once semantics. - */ - protected abstract void performCleanup(); - - /** - * This method always throws {@link UnsupportedOperationException}. - * Enqueuing details of {@link Cleaner.Cleanable} - * are a private implementation detail. - * - * @throws UnsupportedOperationException always - */ - @Override - public final boolean isEnqueued() { - throw new UnsupportedOperationException("isEnqueued"); - } - - /** - * This method always throws {@link UnsupportedOperationException}. - * Enqueuing details of {@link Cleaner.Cleanable} - * are a private implementation detail. - * - * @throws UnsupportedOperationException always - */ - @Override - public final boolean enqueue() { - throw new UnsupportedOperationException("enqueue"); - } - } - - /** - * WeakCleanable subclasses efficiently encapsulate cleanup state and - * the cleaning action. - * Subclasses implement the abstract {@link #performCleanup()} method - * to provide the cleaning action. - * When constructed, the object reference and the {@link Cleanable Cleanable} - * are registered with the {@link Cleaner}. - * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the - * referent becomes weakly reachable. - */ - public static abstract class WeakCleanable extends WeakReference - implements Cleaner.Cleanable { - - /** - * Links to previous and next in a doubly-linked list. - */ - WeakCleanable prev = this, next = this; - - /** - * The CleanerImpl for this Cleanable. - */ - private final CleanerImpl cleanerImpl; - - /** - * Constructs new {@code WeakCleanableReference} with - * {@code non-null referent} and {@code non-null cleaner}. - * The {@code cleaner} is not retained by this reference; it is only used - * to register the newly constructed {@link Cleaner.Cleanable Cleanable}. - * - * @param referent the referent to track - * @param cleaner the {@code Cleaner} to register new reference with - */ - public WeakCleanable(T referent, Cleaner cleaner) { - super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue); - cleanerImpl = getCleanerImpl(cleaner); - insert(); - - // TODO: Replace getClass() with ReachabilityFence when it is available - cleaner.getClass(); - referent.getClass(); - } - - /** - * Construct a new root of the list; not inserted. - */ - WeakCleanable(CleanerImpl cleanerImpl) { - super(null, null); - this.cleanerImpl = cleanerImpl; - } - - /** - * Insert this WeakCleanableReference after the list head. - */ - private void insert() { - final WeakCleanable list = cleanerImpl.weakCleanableList; - synchronized (list) { - prev = list; - next = list.next; - next.prev = this; - list.next = this; - } - } - - /** - * Remove this WeakCleanableReference from the list. - * - * @return true if Cleanable was removed or false if not because - * it had already been removed before - */ - private boolean remove() { - WeakCleanable list = cleanerImpl.weakCleanableList; - synchronized (list) { - if (next != this) { - next.prev = prev; - prev.next = next; - prev = this; - next = this; - return true; - } - return false; - } - } - - /** - * Returns true if the list's next reference refers to itself. - * - * @return true if the list is empty - */ - boolean isListEmpty() { - WeakCleanable list = cleanerImpl.weakCleanableList; - synchronized (list) { - return list == list.next; - } - } - - /** - * Unregister this WeakCleanable reference and invoke {@link #performCleanup()}, - * ensuring at-most-once semantics. - */ - @Override - public final void clean() { - if (remove()) { - super.clear(); - performCleanup(); - } - } - - /** - * Unregister this WeakCleanable and clear the reference. - * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. - */ - @Override - public void clear() { - if (remove()) { - super.clear(); - } - } - - /** - * The {@code performCleanup} abstract method is overridden - * to implement the cleaning logic. - * The {@code performCleanup} method should not be called except - * by the {@link #clean} method which ensures at most once semantics. - */ - protected abstract void performCleanup(); - - /** - * This method always throws {@link UnsupportedOperationException}. - * Enqueuing details of {@link java.lang.ref.Cleaner.Cleanable} - * are a private implementation detail. - * - * @throws UnsupportedOperationException always - */ - @Override - public final boolean isEnqueued() { - throw new UnsupportedOperationException("isEnqueued"); - } - - /** - * This method always throws {@link UnsupportedOperationException}. - * Enqueuing details of {@link java.lang.ref.Cleaner.Cleanable} - * are a private implementation detail. - * - * @throws UnsupportedOperationException always - */ - @Override - public final boolean enqueue() { - throw new UnsupportedOperationException("enqueue"); - } - } - - /** - * SoftCleanable subclasses efficiently encapsulate cleanup state and - * the cleaning action. - * Subclasses implement the abstract {@link #performCleanup()} method - * to provide the cleaning action. - * When constructed, the object reference and the {@link Cleanable Cleanable} - * are registered with the {@link Cleaner}. - * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the - * referent becomes softly reachable. - */ - public static abstract class SoftCleanable extends SoftReference - implements Cleaner.Cleanable { - - /** - * Links to previous and next in a doubly-linked list. - */ - SoftCleanable prev = this, next = this; - - /** - * The CleanerImpl for this Cleanable. - */ - private final CleanerImpl cleanerImpl; - - /** - * Constructs new {@code SoftCleanableReference} with - * {@code non-null referent} and {@code non-null cleaner}. - * The {@code cleaner} is not retained by this reference; it is only used - * to register the newly constructed {@link Cleaner.Cleanable Cleanable}. - * - * @param referent the referent to track - * @param cleaner the {@code Cleaner} to register with - */ - public SoftCleanable(T referent, Cleaner cleaner) { - super(Objects.requireNonNull(referent), getCleanerImpl(cleaner).queue); - cleanerImpl = getCleanerImpl(cleaner); - insert(); - - // TODO: Replace getClass() with ReachabilityFence when it is available - cleaner.getClass(); - referent.getClass(); - } - - /** - * Construct a new root of the list; not inserted. - */ - SoftCleanable(CleanerImpl cleanerImpl) { - super(null, null); - this.cleanerImpl = cleanerImpl; - } - - /** - * Insert this SoftCleanableReference after the list head. - */ - private void insert() { - final SoftCleanable list = cleanerImpl.softCleanableList; - synchronized (list) { - prev = list; - next = list.next; - next.prev = this; - list.next = this; - } - } - - /** - * Remove this SoftCleanableReference from the list. - * - * @return true if Cleanable was removed or false if not because - * it had already been removed before - */ - private boolean remove() { - SoftCleanable list = cleanerImpl.softCleanableList; - synchronized (list) { - if (next != this) { - next.prev = prev; - prev.next = next; - prev = this; - next = this; - return true; - } - return false; - } - } - - /** - * Returns true if the list's next reference refers to itself. - * - * @return true if the list is empty - */ - boolean isListEmpty() { - SoftCleanable list = cleanerImpl.softCleanableList; - synchronized (list) { - return list == list.next; - } - } - - /** - * Unregister this SoftCleanable reference and invoke {@link #performCleanup()}, - * ensuring at-most-once semantics. - */ - @Override - public final void clean() { - if (remove()) { - super.clear(); - performCleanup(); - } - } - - /** - * Unregister this SoftCleanable and clear the reference. - * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. - */ - @Override - public void clear() { - if (remove()) { - super.clear(); - } - } - - /** - * The {@code performCleanup} abstract method is overridden - * to implement the cleaning logic. - * The {@code performCleanup} method should not be called except - * by the {@link #clean} method which ensures at most once semantics. - */ - protected abstract void performCleanup(); - - /** - * This method always throws {@link UnsupportedOperationException}. - * Enqueuing details of {@link Cleaner.Cleanable} - * are a private implementation detail. - * - * @throws UnsupportedOperationException always - */ - @Override - public final boolean isEnqueued() { - throw new UnsupportedOperationException("isEnqueued"); - } - - /** - * This method always throws {@link UnsupportedOperationException}. - * Enqueuing details of {@link Cleaner.Cleanable} - * are a private implementation detail. - * - * @throws UnsupportedOperationException always - */ - @Override - public final boolean enqueue() { - throw new UnsupportedOperationException("enqueue"); - } - } - - /** - * Perform cleaning on an unreachable PhantomReference. - */ - public static final class PhantomCleanableRef extends PhantomCleanable { - private final Runnable action; - - /** - * Constructor for a phantom cleanable reference. - * @param obj the object to monitor - * @param cleaner the cleaner - * @param action the action Runnable - */ - public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) { - super(obj, cleaner); - this.action = action; - } - - /** - * Constructor used only for root of phantom cleanable list. - * @param cleanerImpl the cleanerImpl - */ - PhantomCleanableRef(CleanerImpl cleanerImpl) { - super(cleanerImpl); - this.action = null; - } - - @Override - protected void performCleanup() { - action.run(); - } - - /** - * Prevent access to referent even when it is still alive. - * - * @throws UnsupportedOperationException always - */ - @Override - public Object get() { - throw new UnsupportedOperationException("get"); - } - - /** - * Direct clearing of the referent is not supported. - * - * @throws UnsupportedOperationException always - */ - @Override - public void clear() { - throw new UnsupportedOperationException("clear"); - } - } - - /** - * Perform cleaning on an unreachable WeakReference. - */ - public static final class WeakCleanableRef extends WeakCleanable { - private final Runnable action; - - /** - * Constructor for a weak cleanable reference. - * @param obj the object to monitor - * @param cleaner the cleaner - * @param action the action Runnable - */ - WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) { - super(obj, cleaner); - this.action = action; - } - - /** - * Constructor used only for root of weak cleanable list. - * @param cleanerImpl the cleanerImpl - */ - WeakCleanableRef(CleanerImpl cleanerImpl) { - super(cleanerImpl); - this.action = null; - } - - @Override - protected void performCleanup() { - action.run(); - } - - /** - * Prevent access to referent even when it is still alive. - * - * @throws UnsupportedOperationException always - */ - @Override - public Object get() { - throw new UnsupportedOperationException("get"); - } - - /** - * Direct clearing of the referent is not supported. - * - * @throws UnsupportedOperationException always - */ - @Override - public void clear() { - throw new UnsupportedOperationException("clear"); - } - } - - /** - * Perform cleaning on an unreachable SoftReference. - */ - public static final class SoftCleanableRef extends SoftCleanable { - private final Runnable action; - - /** - * Constructor for a soft cleanable reference. - * @param obj the object to monitor - * @param cleaner the cleaner - * @param action the action Runnable - */ - SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) { - super(obj, cleaner); - this.action = action; - } - - /** - * Constructor used only for root of soft cleanable list. - * @param cleanerImpl the cleanerImpl - */ - SoftCleanableRef(CleanerImpl cleanerImpl) { - super(cleanerImpl); - this.action = null; - } - - @Override - protected void performCleanup() { - action.run(); - } - - /** - * Prevent access to referent even when it is still alive. - * - * @throws UnsupportedOperationException always - */ - @Override - public Object get() { - throw new UnsupportedOperationException("get"); - } - - /** - * Direct clearing of the referent is not supported. - * - * @throws UnsupportedOperationException always - */ - @Override - public void clear() { - throw new UnsupportedOperationException("clear"); - } - - } - - /** - * A ThreadFactory for InnocuousThreads. - * The factory is a singleton. - */ - static final class InnocuousThreadFactory implements ThreadFactory { - final static ThreadFactory factory = new InnocuousThreadFactory(); - - static ThreadFactory factory() { - return factory; - } - - public Thread newThread(Runnable r) { - return AccessController.doPrivileged((PrivilegedAction) () -> { - Thread t = new InnocuousThread(r); - t.setPriority(Thread.MAX_PRIORITY - 2); - t.setName("Cleaner-" + t.getId()); - return t; - }); - } - } - -} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/perf/Perf.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/perf/Perf.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.perf; + +import java.nio.ByteBuffer; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import jdk.internal.ref.CleanerFactory; + +/** + * The Perf class provides the ability to attach to an instrumentation + * buffer maintained by a Java virtual machine. The instrumentation + * buffer may be for the Java virtual machine running the methods of + * this class or it may be for another Java virtual machine on the + * same system. + *

+ * In addition, this class provides methods to create instrumentation + * objects in the instrumentation buffer for the Java virtual machine + * that is running these methods. It also contains methods for acquiring + * the value of a platform specific high resolution clock for time + * stamp and interval measurement purposes. + * + * @author Brian Doherty + * @since 1.4.2 + * @see #getPerf + * @see jdk.internal.perf.Perf.GetPerfAction + * @see java.nio.ByteBuffer + */ +public final class Perf { + + private static Perf instance; + + private static final int PERF_MODE_RO = 0; + private static final int PERF_MODE_RW = 1; + + private Perf() { } // prevent instantiation + + /** + * The GetPerfAction class is a convenience class for acquiring access + * to the singleton Perf instance using the + * AccessController.doPrivileged() method. + *

+ * An instance of this class can be used as the argument to + * AccessController.doPrivileged(PrivilegedAction). + *

Here is a suggested idiom for use of this class: + * + *

{@code
+     * class MyTrustedClass {
+     *   private static final Perf perf =
+     *       AccessController.doPrivileged(new Perf.GetPerfAction());
+     *   ...
+     * }
+     * }
+ *

+ * In the presence of a security manager, the MyTrustedClass + * class in the above example will need to be granted the + * "sun.misc.Perf.getPerf" RuntimePermission + * permission in order to successfully acquire the singleton Perf instance. + *

+ * Please note that the "sun.misc.Perf.getPerf" permission + * is not a JDK specified permission. + * + * @see java.security.AccessController#doPrivileged(PrivilegedAction) + * @see java.lang.RuntimePermission + */ + public static class GetPerfAction implements PrivilegedAction + { + /** + * Run the Perf.getPerf() method in a privileged context. + * + * @see #getPerf + */ + public Perf run() { + return getPerf(); + } + } + + /** + * Return a reference to the singleton Perf instance. + *

+ * The getPerf() method returns the singleton instance of the Perf + * class. The returned object provides the caller with the capability + * for accessing the instrumentation buffer for this or another local + * Java virtual machine. + *

+ * If a security manager is installed, its checkPermission + * method is called with a RuntimePermission with a target + * of "sun.misc.Perf.getPerf". A security exception will result + * if the caller has not been granted this permission. + *

+ * Access to the returned Perf object should be protected + * by its caller and not passed on to untrusted code. This object can + * be used to attach to the instrumentation buffer provided by this Java + * virtual machine or for those of other Java virtual machines running + * on the same system. The instrumentation buffer may contain senstitive + * information. API's built on top of this interface may want to provide + * finer grained access control to the contents of individual + * instrumentation objects contained within the buffer. + *

+ * Please note that the "sun.misc.Perf.getPerf" permission + * is not a JDK specified permission. + * + * @return A reference to the singleton Perf instance. + * @throws SecurityException if a security manager exists and its + * checkPermission method doesn't allow access + * to the "jdk.internal.perf.Perf.getPerf"" target. + * @see java.lang.RuntimePermission + * @see #attach + */ + public static Perf getPerf() + { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + Permission perm = new RuntimePermission("jdk.internal.perf.Perf.getPerf"); + security.checkPermission(perm); + } + + return instance; + } + + /** + * Attach to the instrumentation buffer for the specified Java virtual + * machine. + *

+ * This method will attach to the instrumentation buffer for the + * specified virtual machine. It returns a ByteBuffer object + * that is initialized to access the instrumentation buffer for the + * indicated Java virtual machine. The lvmid parameter is + * a integer value that uniquely identifies the target local Java virtual + * machine. It is typically, but not necessarily, the process id of + * the target Java virtual machine. + *

+ * If the lvmid identifies a Java virtual machine different + * from the one running this method, then the coherency characteristics + * of the buffer are implementation dependent. Implementations that do + * not support named, coherent, shared memory may return a + * ByteBuffer object that contains only a snap shot of the + * data in the instrumentation buffer. Implementations that support named, + * coherent, shared memory, may return a ByteBuffer object + * that will be changing dynamically over time as the target Java virtual + * machine updates its mapping of this buffer. + *

+ * If the lvmid is 0 or equal to the actual lvmid + * for the Java virtual machine running this method, then the returned + * ByteBuffer object will always be coherent and dynamically + * changing. + *

+ * The attach mode specifies the access permissions requested for the + * instrumentation buffer of the target virtual machine. The permitted + * access permissions are: + *

    + *
  • "r" - Read only access. This Java virtual machine has only + * read access to the instrumentation buffer for the target Java + * virtual machine. + *
  • "rw" - Read/Write access. This Java virtual machine has read and + * write access to the instrumentation buffer for the target Java virtual + * machine. This mode is currently not supported and is reserved for + * future enhancements. + *
+ * + * @param lvmid an integer that uniquely identifies the + * target local Java virtual machine. + * @param mode a string indicating the attach mode. + * @return ByteBuffer a direct allocated byte buffer + * @throws IllegalArgumentException The lvmid or mode was invalid. + * @throws IOException An I/O error occurred while trying to acquire + * the instrumentation buffer. + * @throws OutOfMemoryError The instrumentation buffer could not be mapped + * into the virtual machine's address space. + * @see java.nio.ByteBuffer + */ + public ByteBuffer attach(int lvmid, String mode) + throws IllegalArgumentException, IOException + { + if (mode.compareTo("r") == 0) { + return attachImpl(null, lvmid, PERF_MODE_RO); + } + else if (mode.compareTo("rw") == 0) { + return attachImpl(null, lvmid, PERF_MODE_RW); + } + else { + throw new IllegalArgumentException("unknown mode"); + } + } + + /** + * Attach to the instrumentation buffer for the specified Java virtual + * machine owned by the given user. + *

+ * This method behaves just as the attach(int lvmid, String mode) + * method, except that it only searches for Java virtual machines + * owned by the specified user. + * + * @param user A String object containing the + * name of the user that owns the target Java + * virtual machine. + * @param lvmid an integer that uniquely identifies the + * target local Java virtual machine. + * @param mode a string indicating the attach mode. + * @return ByteBuffer a direct allocated byte buffer + * @throws IllegalArgumentException The lvmid or mode was invalid. + * @throws IOException An I/O error occurred while trying to acquire + * the instrumentation buffer. + * @throws OutOfMemoryError The instrumentation buffer could not be mapped + * into the virtual machine's address space. + * @see java.nio.ByteBuffer + */ + public ByteBuffer attach(String user, int lvmid, String mode) + throws IllegalArgumentException, IOException + { + if (mode.compareTo("r") == 0) { + return attachImpl(user, lvmid, PERF_MODE_RO); + } + else if (mode.compareTo("rw") == 0) { + return attachImpl(user, lvmid, PERF_MODE_RW); + } + else { + throw new IllegalArgumentException("unknown mode"); + } + } + + /** + * Call the implementation specific attach method. + *

+ * This method calls into the Java virtual machine to perform the platform + * specific attach method. Buffers returned from this method are + * internally managed as PhantomRefereces to provide for + * guaranteed, secure release of the native resources. + * + * @param user A String object containing the + * name of the user that owns the target Java + * virtual machine. + * @param lvmid an integer that uniquely identifies the + * target local Java virtual machine. + * @param mode a string indicating the attach mode. + * @return ByteBuffer a direct allocated byte buffer + * @throws IllegalArgumentException The lvmid or mode was invalid. + * @throws IOException An I/O error occurred while trying to acquire + * the instrumentation buffer. + * @throws OutOfMemoryError The instrumentation buffer could not be mapped + * into the virtual machine's address space. + */ + private ByteBuffer attachImpl(String user, int lvmid, int mode) + throws IllegalArgumentException, IOException + { + final ByteBuffer b = attach(user, lvmid, mode); + + if (lvmid == 0) { + // The native instrumentation buffer for this Java virtual + // machine is never unmapped. + return b; + } + else { + // This is an instrumentation buffer for another Java virtual + // machine with native resources that need to be managed. We + // create a duplicate of the native ByteBuffer and manage it + // with a Cleaner. When the duplicate becomes phantom reachable, + // the native resources will be released. + + final ByteBuffer dup = b.duplicate(); + + CleanerFactory.cleaner() + .register(dup, new CleanerAction(instance, b)); + return dup; + } + } + + private static class CleanerAction implements Runnable { + private final ByteBuffer bb; + private final Perf perf; + CleanerAction(Perf perf, ByteBuffer bb) { + this.perf = perf; + this.bb = bb; + } + public void run() { + try { + perf.detach(bb); + } catch (Throwable th) { + // avoid crashing the reference handler thread, + // but provide for some diagnosability + assert false : th.toString(); + } + } + } + + /** + * Native method to perform the implementation specific attach mechanism. + *

+ * The implementation of this method may return distinct or identical + * ByteBuffer objects for two distinct calls requesting + * attachment to the same Java virtual machine. + *

+ * For the Sun HotSpot JVM, two distinct calls to attach to the same + * target Java virtual machine will result in two distinct ByteBuffer + * objects returned by this method. This may change in a future release. + * + * @param user A String object containing the + * name of the user that owns the target Java + * virtual machine. + * @param lvmid an integer that uniquely identifies the + * target local Java virtual machine. + * @param mode a string indicating the attach mode. + * @return ByteBuffer a direct allocated byte buffer + * @throws IllegalArgumentException The lvmid or mode was invalid. + * @throws IOException An I/O error occurred while trying to acquire + * the instrumentation buffer. + * @throws OutOfMemoryError The instrumentation buffer could not be mapped + * into the virtual machine's address space. + */ + private native ByteBuffer attach(String user, int lvmid, int mode) + throws IllegalArgumentException, IOException; + + /** + * Native method to perform the implementation specific detach mechanism. + *

+ * If this method is passed a ByteBuffer object that is + * not created by the attach method, then the results of + * this method are undefined, with unpredictable and potentially damaging + * effects to the Java virtual machine. To prevent accidental or malicious + * use of this method, all native ByteBuffer created by the + * attach method are managed internally as PhantomReferences + * and resources are freed by the system. + *

+ * If this method is passed a ByteBuffer object created + * by the attach method with a lvmid for the Java virtual + * machine running this method (lvmid=0, for example), then the detach + * request is silently ignored. + * + * @param bb A direct allocated byte buffer created by the + * attach method. + * @see java.nio.ByteBuffer + * @see #attach + */ + private native void detach(ByteBuffer bb); + + /** + * Create a long scalar entry in the instrumentation buffer + * with the given variability characteristic, units, and initial value. + *

+ * Access to the instrument is provided through the returned + * ByteBuffer object. Typically, this object should be wrapped + * with LongBuffer view object. + * + * @param variability the variability characteristic for this entry. + * @param units the units for this entry. + * @param name the name of this entry. + * @param value the initial value for this entry. + * @return ByteBuffer a direct allocated ByteBuffer object that + * allows write access to a native memory location + * containing a long value. + * + * see sun.misc.perf.Variability + * see sun.misc.perf.Units + * @see java.nio.ByteBuffer + */ + public native ByteBuffer createLong(String name, int variability, + int units, long value); + + /** + * Create a String entry in the instrumentation buffer with + * the given variability characteristic, units, and initial value. + *

+ * The maximum length of the String stored in this string + * instrument is given in by maxLength parameter. Updates + * to this instrument with String values with lengths greater + * than maxLength will be truncated to maxLength. + * The truncated value will be terminated by a null character. + *

+ * The underlying implementation may further limit the length of the + * value, but will continue to preserve the null terminator. + *

+ * Access to the instrument is provided through the returned + * ByteBuffer object. + * + * @param variability the variability characteristic for this entry. + * @param units the units for this entry. + * @param name the name of this entry. + * @param value the initial value for this entry. + * @param maxLength the maximum string length for this string + * instrument. + * @return ByteBuffer a direct allocated ByteBuffer that allows + * write access to a native memory location + * containing a long value. + * + * see sun.misc.perf.Variability + * see sun.misc.perf.Units + * @see java.nio.ByteBuffer + */ + public ByteBuffer createString(String name, int variability, + int units, String value, int maxLength) + { + byte[] v = getBytes(value); + byte[] v1 = new byte[v.length+1]; + System.arraycopy(v, 0, v1, 0, v.length); + v1[v.length] = '\0'; + return createByteArray(name, variability, units, v1, Math.max(v1.length, maxLength)); + } + + /** + * Create a String entry in the instrumentation buffer with + * the given variability characteristic, units, and initial value. + *

+ * The maximum length of the String stored in this string + * instrument is implied by the length of the value parameter. + * Subsequent updates to the value of this instrument will be truncated + * to this implied maximum length. The truncated value will be terminated + * by a null character. + *

+ * The underlying implementation may further limit the length of the + * initial or subsequent value, but will continue to preserve the null + * terminator. + *

+ * Access to the instrument is provided through the returned + * ByteBuffer object. + * + * @param variability the variability characteristic for this entry. + * @param units the units for this entry. + * @param name the name of this entry. + * @param value the initial value for this entry. + * @return ByteBuffer a direct allocated ByteBuffer that allows + * write access to a native memory location + * containing a long value. + * + * see sun.misc.perf.Variability + * see sun.misc.perf.Units + * @see java.nio.ByteBuffer + */ + public ByteBuffer createString(String name, int variability, + int units, String value) + { + byte[] v = getBytes(value); + byte[] v1 = new byte[v.length+1]; + System.arraycopy(v, 0, v1, 0, v.length); + v1[v.length] = '\0'; + return createByteArray(name, variability, units, v1, v1.length); + } + + /** + * Create a byte vector entry in the instrumentation buffer + * with the given variability characteristic, units, and initial value. + *

+ * The maxLength parameter limits the size of the byte + * array instrument such that the initial or subsequent updates beyond + * this length are silently ignored. No special handling of truncated + * updates is provided. + *

+ * The underlying implementation may further limit the length of the + * length of the initial or subsequent value. + *

+ * Access to the instrument is provided through the returned + * ByteBuffer object. + * + * @param variability the variability characteristic for this entry. + * @param units the units for this entry. + * @param name the name of this entry. + * @param value the initial value for this entry. + * @param maxLength the maximum length of this byte array. + * @return ByteBuffer a direct allocated byte buffer that allows + * write access to a native memory location + * containing a long value. + * + * see sun.misc.perf.Variability + * see sun.misc.perf.Units + * @see java.nio.ByteBuffer + */ + public native ByteBuffer createByteArray(String name, int variability, + int units, byte[] value, + int maxLength); + + + /** + * convert string to an array of UTF-8 bytes + */ + private static byte[] getBytes(String s) + { + byte[] bytes = null; + + try { + bytes = s.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException e) { + // ignore, UTF-8 encoding is always known + } + + return bytes; + } + + /** + * Return the value of the High Resolution Counter. + * + * The High Resolution Counter returns the number of ticks since + * since the start of the Java virtual machine. The resolution of + * the counter is machine dependent and can be determined from the + * value return by the {@link #highResFrequency} method. + * + * @return the number of ticks of machine dependent resolution since + * the start of the Java virtual machine. + * + * @see #highResFrequency + * @see java.lang.System#currentTimeMillis() + */ + public native long highResCounter(); + + /** + * Returns the frequency of the High Resolution Counter, in ticks per + * second. + * + * This value can be used to convert the value of the High Resolution + * Counter, as returned from a call to the {@link #highResCounter} method, + * into the number of seconds since the start of the Java virtual machine. + * + * @return the frequency of the High Resolution Counter. + * @see #highResCounter + */ + public native long highResFrequency(); + + private static native void registerNatives(); + + static { + registerNatives(); + instance = new Perf(); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.perf; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.LongBuffer; +import java.security.AccessController; + +/** + * Performance counter support for internal JRE classes. + * This class defines a fixed list of counters for the platform + * to use as an interim solution until RFE# 6209222 is implemented. + * The perf counters will be created in the jvmstat perf buffer + * that the HotSpot VM creates. The default size is 32K and thus + * the number of counters is bounded. You can alter the size + * with {@code -XX:PerfDataMemorySize=} option. If there is + * insufficient memory in the jvmstat perf buffer, the C heap memory + * will be used and thus the application will continue to run if + * the counters added exceeds the buffer size but the counters + * will be missing. + * + * See HotSpot jvmstat implementation for certain circumstances + * that the jvmstat perf buffer is not supported. + * + */ +public class PerfCounter { + private static final Perf perf = + AccessController.doPrivileged(new Perf.GetPerfAction()); + + // Must match values defined in hotspot/src/share/vm/runtime/perfdata.hpp + private static final int V_Constant = 1; + private static final int V_Monotonic = 2; + private static final int V_Variable = 3; + private static final int U_None = 1; + + private final String name; + private final LongBuffer lb; + + private PerfCounter(String name, int type) { + this.name = name; + ByteBuffer bb = perf.createLong(name, type, U_None, 0L); + bb.order(ByteOrder.nativeOrder()); + this.lb = bb.asLongBuffer(); + } + + static PerfCounter newPerfCounter(String name) { + return new PerfCounter(name, V_Variable); + } + + static PerfCounter newConstantPerfCounter(String name) { + PerfCounter c = new PerfCounter(name, V_Constant); + return c; + } + + /** + * Returns the current value of the perf counter. + */ + public synchronized long get() { + return lb.get(0); + } + + /** + * Sets the value of the perf counter to the given newValue. + */ + public synchronized void set(long newValue) { + lb.put(0, newValue); + } + + /** + * Adds the given value to the perf counter. + */ + public synchronized void add(long value) { + long res = get() + value; + lb.put(0, res); + } + + /** + * Increments the perf counter with 1. + */ + public void increment() { + add(1); + } + + /** + * Adds the given interval to the perf counter. + */ + public void addTime(long interval) { + add(interval); + } + + /** + * Adds the elapsed time from the given start time (ns) to the perf counter. + */ + public void addElapsedTimeFrom(long startTime) { + add(System.nanoTime() - startTime); + } + + @Override + public String toString() { + return name + " = " + get(); + } + + static class CoreCounters { + static final PerfCounter pdt = newPerfCounter("sun.classloader.parentDelegationTime"); + static final PerfCounter lc = newPerfCounter("sun.classloader.findClasses"); + static final PerfCounter lct = newPerfCounter("sun.classloader.findClassTime"); + static final PerfCounter rcbt = newPerfCounter("sun.urlClassLoader.readClassBytesTime"); + static final PerfCounter zfc = newPerfCounter("sun.zip.zipFiles"); + static final PerfCounter zfot = newPerfCounter("sun.zip.zipFile.openTime"); + } + + static class WindowsClientCounters { + static final PerfCounter d3dAvailable = newConstantPerfCounter("sun.java2d.d3d.available"); + } + + /** + * Number of findClass calls + */ + public static PerfCounter getFindClasses() { + return CoreCounters.lc; + } + + /** + * Time (ns) spent in finding classes that includes + * lookup and read class bytes and defineClass + */ + public static PerfCounter getFindClassTime() { + return CoreCounters.lct; + } + + /** + * Time (ns) spent in finding classes + */ + public static PerfCounter getReadClassBytesTime() { + return CoreCounters.rcbt; + } + + /** + * Time (ns) spent in the parent delegation to + * the parent of the defining class loader + */ + public static PerfCounter getParentDelegationTime() { + return CoreCounters.pdt; + } + + /** + * Number of zip files opened. + */ + public static PerfCounter getZipFileCount() { + return CoreCounters.zfc; + } + + /** + * Time (ns) spent in opening the zip files that + * includes building the entries hash table + */ + public static PerfCounter getZipFileOpenTime() { + return CoreCounters.zfot; + } + + /** + * D3D graphic pipeline available + */ + public static PerfCounter getD3DAvailable() { + return WindowsClientCounters.d3dAvailable; + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/ref/CleanerFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/ref/CleanerFactory.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.ref; + +import java.lang.ref.Cleaner; + +/** + * CleanerFactory provides a Cleaner for use within OpenJDK modules. + * The cleaner is created on the first reference to the CleanerFactory. + */ +public final class CleanerFactory { + + /* The common Cleaner. */ + private final static Cleaner commonCleaner = Cleaner.create(); + + /** + * Cleaner for use within OpenJDK modules. + * + * @return a Cleaner for use within OpenJDK modules + */ + public static Cleaner cleaner() { + return commonCleaner; + } + +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.ref; + +import java.lang.ref.Cleaner; +import java.lang.ref.Cleaner.Cleanable; +import java.lang.ref.ReferenceQueue; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.concurrent.ThreadFactory; +import java.util.function.Function; + +import sun.misc.InnocuousThread; + +/** + * CleanerImpl manages a set of object references and corresponding cleaning actions. + * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}. + */ +public final class CleanerImpl { + + /** + * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. + */ + private static Function cleanerImplAccess = null; + + /** + * Heads of a CleanableList for each reference type. + */ + final PhantomCleanable phantomCleanableList; + + final WeakCleanable weakCleanableList; + + final SoftCleanable softCleanableList; + + // The ReferenceQueue of pending cleaning actions + final ReferenceQueue queue; + + /** + * Called by Cleaner static initialization to provide the function + * to map from Cleaner to CleanerImpl. + * @param access a function to map from Cleaner to CleanerImpl + */ + public static void setCleanerImplAccess(Function access) { + if (cleanerImplAccess == null) { + cleanerImplAccess = access; + } else { + throw new InternalError("cleanerImplAccess"); + } + } + + /** + * Called to get the CleanerImpl for a Cleaner. + * @param cleaner the cleaner + * @return the corresponding CleanerImpl + */ + static CleanerImpl getCleanerImpl(Cleaner cleaner) { + return cleanerImplAccess.apply(cleaner); + } + + /** + * Constructor for CleanerImpl. + */ + public CleanerImpl() { + queue = new ReferenceQueue<>(); + phantomCleanableList = new PhantomCleanableRef(); + weakCleanableList = new WeakCleanableRef(); + softCleanableList = new SoftCleanableRef(); + } + + /** + * Starts the Cleaner implementation. + * Ensure this is the CleanerImpl for the Cleaner. + * When started waits for Cleanables to be queued. + * @param cleaner the cleaner + * @param threadFactory the thread factory + */ + public void start(Cleaner cleaner, ThreadFactory threadFactory) { + if (getCleanerImpl(cleaner) != this) { + throw new AssertionError("wrong cleaner"); + } + // schedule a nop cleaning action for the cleaner, so the associated thread + // will continue to run at least until the cleaner is reclaimable. + new PhantomCleanableRef(cleaner, cleaner, () -> {}); + + if (threadFactory == null) { + threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); + } + + // now that there's at least one cleaning action, for the cleaner, + // we can start the associated thread, which runs until + // all cleaning actions have been run. + Thread thread = threadFactory.newThread(this::run); + thread.setDaemon(true); + thread.start(); + } + + /** + * Process queued Cleanables as long as the cleanable lists are not empty. + * A Cleanable is in one of the lists for each Object and for the Cleaner + * itself. + * Terminates when the Cleaner is no longer reachable and + * has been cleaned and there are no more Cleanable instances + * for which the object is reachable. + *

+ * If the thread is a ManagedLocalsThread, the threadlocals + * are erased before each cleanup + */ + private void run() { + Thread t = Thread.currentThread(); + InnocuousThread mlThread = (t instanceof InnocuousThread) + ? (InnocuousThread) t + : null; + while (!phantomCleanableList.isListEmpty() || + !weakCleanableList.isListEmpty() || + !softCleanableList.isListEmpty()) { + if (mlThread != null) { + // Clear the thread locals + mlThread.eraseThreadLocals(); + } + try { + // Wait for a Ref, with a timeout to avoid getting hung + // due to a race with clear/clean + Cleanable ref = (Cleanable) queue.remove(60 * 1000L); + if (ref != null) { + ref.clean(); + } + } catch (InterruptedException i) { + continue; // ignore the interruption + } catch (Throwable e) { + // ignore exceptions from the cleanup action + } + } + } + + /** + * Perform cleaning on an unreachable PhantomReference. + */ + public static final class PhantomCleanableRef extends PhantomCleanable { + private final Runnable action; + + /** + * Constructor for a phantom cleanable reference. + * @param obj the object to monitor + * @param cleaner the cleaner + * @param action the action Runnable + */ + public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) { + super(obj, cleaner); + this.action = action; + } + + /** + * Constructor used only for root of phantom cleanable list. + */ + PhantomCleanableRef() { + super(); + this.action = null; + } + + @Override + protected void performCleanup() { + action.run(); + } + + /** + * Prevent access to referent even when it is still alive. + * + * @throws UnsupportedOperationException always + */ + @Override + public Object get() { + throw new UnsupportedOperationException("get"); + } + + /** + * Direct clearing of the referent is not supported. + * + * @throws UnsupportedOperationException always + */ + @Override + public void clear() { + throw new UnsupportedOperationException("clear"); + } + } + + /** + * Perform cleaning on an unreachable WeakReference. + */ + public static final class WeakCleanableRef extends WeakCleanable { + private final Runnable action; + + /** + * Constructor for a weak cleanable reference. + * @param obj the object to monitor + * @param cleaner the cleaner + * @param action the action Runnable + */ + WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) { + super(obj, cleaner); + this.action = action; + } + + /** + * Constructor used only for root of weak cleanable list. + */ + WeakCleanableRef() { + super(); + this.action = null; + } + + @Override + protected void performCleanup() { + action.run(); + } + + /** + * Prevent access to referent even when it is still alive. + * + * @throws UnsupportedOperationException always + */ + @Override + public Object get() { + throw new UnsupportedOperationException("get"); + } + + /** + * Direct clearing of the referent is not supported. + * + * @throws UnsupportedOperationException always + */ + @Override + public void clear() { + throw new UnsupportedOperationException("clear"); + } + } + + /** + * Perform cleaning on an unreachable SoftReference. + */ + public static final class SoftCleanableRef extends SoftCleanable { + private final Runnable action; + + /** + * Constructor for a soft cleanable reference. + * @param obj the object to monitor + * @param cleaner the cleaner + * @param action the action Runnable + */ + SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) { + super(obj, cleaner); + this.action = action; + } + + /** + * Constructor used only for root of soft cleanable list. + */ + SoftCleanableRef() { + super(); + this.action = null; + } + + @Override + protected void performCleanup() { + action.run(); + } + + /** + * Prevent access to referent even when it is still alive. + * + * @throws UnsupportedOperationException always + */ + @Override + public Object get() { + throw new UnsupportedOperationException("get"); + } + + /** + * Direct clearing of the referent is not supported. + * + * @throws UnsupportedOperationException always + */ + @Override + public void clear() { + throw new UnsupportedOperationException("clear"); + } + + } + + /** + * A ThreadFactory for InnocuousThreads. + * The factory is a singleton. + */ + static final class InnocuousThreadFactory implements ThreadFactory { + final static ThreadFactory factory = new InnocuousThreadFactory(); + + static ThreadFactory factory() { + return factory; + } + + public Thread newThread(Runnable r) { + return AccessController.doPrivileged((PrivilegedAction) () -> { + Thread t = new InnocuousThread(r); + t.setPriority(Thread.MAX_PRIORITY - 2); + t.setName("Cleaner-" + t.getId()); + return t; + }); + } + } + +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/ref/PhantomCleanable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/ref/PhantomCleanable.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.ref; + +import java.lang.ref.Cleaner; +import java.lang.ref.PhantomReference; +import java.util.Objects; + +/** + * PhantomCleanable subclasses efficiently encapsulate cleanup state and + * the cleaning action. + * Subclasses implement the abstract {@link #performCleanup()} method + * to provide the cleaning action. + * When constructed, the object reference and the {@link Cleaner.Cleanable Cleanable} + * are registered with the {@link Cleaner}. + * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the + * referent becomes phantom reachable. + */ +public abstract class PhantomCleanable extends PhantomReference + implements Cleaner.Cleanable { + + /** + * Links to previous and next in a doubly-linked list. + */ + PhantomCleanable prev = this, next = this; + + /** + * The list of PhantomCleanable; synchronizes insert and remove. + */ + private final PhantomCleanable list; + + /** + * Constructs new {@code PhantomCleanable} with + * {@code non-null referent} and {@code non-null cleaner}. + * The {@code cleaner} is not retained; it is only used to + * register the newly constructed {@link Cleaner.Cleanable Cleanable}. + * + * @param referent the referent to track + * @param cleaner the {@code Cleaner} to register with + */ + public PhantomCleanable(T referent, Cleaner cleaner) { + super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue); + this.list = CleanerImpl.getCleanerImpl(cleaner).phantomCleanableList; + insert(); + + // TODO: Replace getClass() with ReachabilityFence when it is available + cleaner.getClass(); + referent.getClass(); + } + + /** + * Construct a new root of the list; not inserted. + */ + PhantomCleanable() { + super(null, null); + this.list = this; + } + + /** + * Insert this PhantomCleanable after the list head. + */ + private void insert() { + synchronized (list) { + prev = list; + next = list.next; + next.prev = this; + list.next = this; + } + } + + /** + * Remove this PhantomCleanable from the list. + * + * @return true if Cleanable was removed or false if not because + * it had already been removed before + */ + private boolean remove() { + synchronized (list) { + if (next != this) { + next.prev = prev; + prev.next = next; + prev = this; + next = this; + return true; + } + return false; + } + } + + /** + * Returns true if the list's next reference refers to itself. + * + * @return true if the list is empty + */ + boolean isListEmpty() { + synchronized (list) { + return list == list.next; + } + } + + /** + * Unregister this PhantomCleanable and invoke {@link #performCleanup()}, + * ensuring at-most-once semantics. + */ + @Override + public final void clean() { + if (remove()) { + super.clear(); + performCleanup(); + } + } + + /** + * Unregister this PhantomCleanable and clear the reference. + * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. + */ + @Override + public void clear() { + if (remove()) { + super.clear(); + } + } + + /** + * The {@code performCleanup} abstract method is overridden + * to implement the cleaning logic. + * The {@code performCleanup} method should not be called except + * by the {@link #clean} method which ensures at most once semantics. + */ + protected abstract void performCleanup(); + + /** + * This method always throws {@link UnsupportedOperationException}. + * Enqueuing details of {@link Cleaner.Cleanable} + * are a private implementation detail. + * + * @throws UnsupportedOperationException always + */ + @Override + public final boolean isEnqueued() { + throw new UnsupportedOperationException("isEnqueued"); + } + + /** + * This method always throws {@link UnsupportedOperationException}. + * Enqueuing details of {@link Cleaner.Cleanable} + * are a private implementation detail. + * + * @throws UnsupportedOperationException always + */ + @Override + public final boolean enqueue() { + throw new UnsupportedOperationException("enqueue"); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/ref/SoftCleanable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/ref/SoftCleanable.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.ref; + +import java.lang.ref.Cleaner; +import java.lang.ref.SoftReference; +import java.util.Objects; + +/** + * SoftCleanable subclasses efficiently encapsulate cleanup state and + * the cleaning action. + * Subclasses implement the abstract {@link #performCleanup()} method + * to provide the cleaning action. + * When constructed, the object reference and the {@link Cleaner.Cleanable Cleanable} + * are registered with the {@link Cleaner}. + * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the + * referent becomes softly reachable. + */ +public abstract class SoftCleanable extends SoftReference + implements Cleaner.Cleanable { + + /** + * Links to previous and next in a doubly-linked list. + */ + SoftCleanable prev = this, next = this; + + /** + * The list of SoftCleanable; synchronizes insert and remove. + */ + private final SoftCleanable list; + + /** + * Constructs new {@code SoftCleanableReference} with + * {@code non-null referent} and {@code non-null cleaner}. + * The {@code cleaner} is not retained by this reference; it is only used + * to register the newly constructed {@link Cleaner.Cleanable Cleanable}. + * + * @param referent the referent to track + * @param cleaner the {@code Cleaner} to register with + */ + public SoftCleanable(T referent, Cleaner cleaner) { + super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue); + list = CleanerImpl.getCleanerImpl(cleaner).softCleanableList; + insert(); + + // TODO: Replace getClass() with ReachabilityFence when it is available + cleaner.getClass(); + referent.getClass(); + } + + /** + * Construct a new root of the list; not inserted. + */ + SoftCleanable() { + super(null, null); + this.list = this; + } + + /** + * Insert this SoftCleanableReference after the list head. + */ + private void insert() { + synchronized (list) { + prev = list; + next = list.next; + next.prev = this; + list.next = this; + } + } + + /** + * Remove this SoftCleanableReference from the list. + * + * @return true if Cleanable was removed or false if not because + * it had already been removed before + */ + private boolean remove() { + synchronized (list) { + if (next != this) { + next.prev = prev; + prev.next = next; + prev = this; + next = this; + return true; + } + return false; + } + } + + /** + * Returns true if the list's next reference refers to itself. + * + * @return true if the list is empty + */ + boolean isListEmpty() { + synchronized (list) { + return list == list.next; + } + } + + /** + * Unregister this SoftCleanable reference and invoke {@link #performCleanup()}, + * ensuring at-most-once semantics. + */ + @Override + public final void clean() { + if (remove()) { + super.clear(); + performCleanup(); + } + } + + /** + * Unregister this SoftCleanable and clear the reference. + * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. + */ + @Override + public void clear() { + if (remove()) { + super.clear(); + } + } + + /** + * The {@code performCleanup} abstract method is overridden + * to implement the cleaning logic. + * The {@code performCleanup} method should not be called except + * by the {@link #clean} method which ensures at most once semantics. + */ + protected abstract void performCleanup(); + + /** + * This method always throws {@link UnsupportedOperationException}. + * Enqueuing details of {@link Cleaner.Cleanable} + * are a private implementation detail. + * + * @throws UnsupportedOperationException always + */ + @Override + public final boolean isEnqueued() { + throw new UnsupportedOperationException("isEnqueued"); + } + + /** + * This method always throws {@link UnsupportedOperationException}. + * Enqueuing details of {@link Cleaner.Cleanable} + * are a private implementation detail. + * + * @throws UnsupportedOperationException always + */ + @Override + public final boolean enqueue() { + throw new UnsupportedOperationException("enqueue"); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/jdk/internal/ref/WeakCleanable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/ref/WeakCleanable.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,178 @@ +package jdk.internal.ref; + +/* + * 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. + */ + +import java.lang.ref.Cleaner; +import java.lang.ref.WeakReference; +import java.util.Objects; + +/** + * WeakCleanable subclasses efficiently encapsulate cleanup state and + * the cleaning action. + * Subclasses implement the abstract {@link #performCleanup()} method + * to provide the cleaning action. + * When constructed, the object reference and the {@link Cleaner.Cleanable Cleanable} + * are registered with the {@link Cleaner}. + * The Cleaner invokes {@link Cleaner.Cleanable#clean() clean} after the + * referent becomes weakly reachable. + */ +public abstract class WeakCleanable extends WeakReference + implements Cleaner.Cleanable { + + /** + * Links to previous and next in a doubly-linked list. + */ + WeakCleanable prev = this, next = this; + + /** + * The list of WeakCleanable; synchronizes insert and remove. + */ + private final WeakCleanable list; + + /** + * Constructs new {@code WeakCleanableReference} with + * {@code non-null referent} and {@code non-null cleaner}. + * The {@code cleaner} is not retained by this reference; it is only used + * to register the newly constructed {@link Cleaner.Cleanable Cleanable}. + * + * @param referent the referent to track + * @param cleaner the {@code Cleaner} to register new reference with + */ + public WeakCleanable(T referent, Cleaner cleaner) { + super(Objects.requireNonNull(referent), CleanerImpl.getCleanerImpl(cleaner).queue); + list = CleanerImpl.getCleanerImpl(cleaner).weakCleanableList; + insert(); + + // TODO: Replace getClass() with ReachabilityFence when it is available + cleaner.getClass(); + referent.getClass(); + } + + /** + * Construct a new root of the list; not inserted. + */ + WeakCleanable() { + super(null, null); + this.list = this; + } + + /** + * Insert this WeakCleanableReference after the list head. + */ + private void insert() { + synchronized (list) { + prev = list; + next = list.next; + next.prev = this; + list.next = this; + } + } + + /** + * Remove this WeakCleanableReference from the list. + * + * @return true if Cleanable was removed or false if not because + * it had already been removed before + */ + private boolean remove() { + synchronized (list) { + if (next != this) { + next.prev = prev; + prev.next = next; + prev = this; + next = this; + return true; + } + return false; + } + } + + /** + * Returns true if the list's next reference refers to itself. + * + * @return true if the list is empty + */ + boolean isListEmpty() { + synchronized (list) { + return list == list.next; + } + } + + /** + * Unregister this WeakCleanable reference and invoke {@link #performCleanup()}, + * ensuring at-most-once semantics. + */ + @Override + public final void clean() { + if (remove()) { + super.clear(); + performCleanup(); + } + } + + /** + * Unregister this WeakCleanable and clear the reference. + * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. + */ + @Override + public void clear() { + if (remove()) { + super.clear(); + } + } + + /** + * The {@code performCleanup} abstract method is overridden + * to implement the cleaning logic. + * The {@code performCleanup} method should not be called except + * by the {@link #clean} method which ensures at most once semantics. + */ + protected abstract void performCleanup(); + + /** + * This method always throws {@link UnsupportedOperationException}. + * Enqueuing details of {@link Cleaner.Cleanable} + * are a private implementation detail. + * + * @throws UnsupportedOperationException always + */ + @Override + public final boolean isEnqueued() { + throw new UnsupportedOperationException("isEnqueued"); + } + + /** + * This method always throws {@link UnsupportedOperationException}. + * Enqueuing details of {@link Cleaner.Cleanable} + * are a private implementation detail. + * + * @throws UnsupportedOperationException always + */ + @Override + public final boolean enqueue() { + throw new UnsupportedOperationException("enqueue"); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/misc/CEFormatException.java --- a/jdk/src/java.base/share/classes/sun/misc/CEFormatException.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.io.IOException; - -public class CEFormatException extends IOException { - static final long serialVersionUID = -7139121221067081482L; - public CEFormatException(String s) { - super(s); - } -} - diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/misc/CEStreamExhausted.java --- a/jdk/src/java.base/share/classes/sun/misc/CEStreamExhausted.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.io.IOException; - -/** This exception is thrown when EOF is reached */ -public class CEStreamExhausted extends IOException { - static final long serialVersionUID = -5889118049525891904L; -} - diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/misc/JarFilter.java --- a/jdk/src/java.base/share/classes/sun/misc/JarFilter.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.io.File; -import java.io.FilenameFilter; - -/** - * This class checks that only jar and zip files are included in the file list. - * This class is used in extension installation support (ExtensionDependency). - * - * @deprecated this class will be removed in a future release. - * @author Michael Colburn - */ -@Deprecated -public class JarFilter implements FilenameFilter { - - public boolean accept(File dir, String name) { - String lower = name.toLowerCase(); - return lower.endsWith(".jar") || lower.endsWith(".zip"); - } -} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/misc/Perf.java --- a/jdk/src/java.base/share/classes/sun/misc/Perf.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,538 +0,0 @@ -/* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.nio.ByteBuffer; -import java.security.Permission; -import java.security.PrivilegedAction; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -/** - * The Perf class provides the ability to attach to an instrumentation - * buffer maintained by a Java virtual machine. The instrumentation - * buffer may be for the Java virtual machine running the methods of - * this class or it may be for another Java virtual machine on the - * same system. - *

- * In addition, this class provides methods to create instrumentation - * objects in the instrumentation buffer for the Java virtual machine - * that is running these methods. It also contains methods for acquiring - * the value of a platform specific high resolution clock for time - * stamp and interval measurement purposes. - * - * @author Brian Doherty - * @since 1.4.2 - * @see #getPerf - * @see sun.misc.Perf$GetPerfAction - * @see java.nio.ByteBuffer - */ -public final class Perf { - - private static Perf instance; - - private static final int PERF_MODE_RO = 0; - private static final int PERF_MODE_RW = 1; - - private Perf() { } // prevent instantiation - - /** - * The GetPerfAction class is a convenience class for acquiring access - * to the singleton Perf instance using the - * AccessController.doPrivileged() method. - *

- * An instance of this class can be used as the argument to - * AccessController.doPrivileged(PrivilegedAction). - *

Here is a suggested idiom for use of this class: - * - *

{@code
-     * class MyTrustedClass {
-     *   private static final Perf perf =
-     *       AccessController.doPrivileged(new Perf.GetPerfAction());
-     *   ...
-     * }
-     * }
- *

- * In the presence of a security manager, the MyTrustedClass - * class in the above example will need to be granted the - * "sun.misc.Perf.getPerf" RuntimePermission - * permission in order to successfully acquire the singleton Perf instance. - *

- * Please note that the "sun.misc.Perf.getPerf" permission - * is not a JDK specified permission. - * - * @see java.security.AccessController#doPrivileged(PrivilegedAction) - * @see java.lang.RuntimePermission - */ - public static class GetPerfAction implements PrivilegedAction - { - /** - * Run the Perf.getPerf() method in a privileged context. - * - * @see #getPerf - */ - public Perf run() { - return getPerf(); - } - } - - /** - * Return a reference to the singleton Perf instance. - *

- * The getPerf() method returns the singleton instance of the Perf - * class. The returned object provides the caller with the capability - * for accessing the instrumentation buffer for this or another local - * Java virtual machine. - *

- * If a security manager is installed, its checkPermission - * method is called with a RuntimePermission with a target - * of "sun.misc.Perf.getPerf". A security exception will result - * if the caller has not been granted this permission. - *

- * Access to the returned Perf object should be protected - * by its caller and not passed on to untrusted code. This object can - * be used to attach to the instrumentation buffer provided by this Java - * virtual machine or for those of other Java virtual machines running - * on the same system. The instrumentation buffer may contain senstitive - * information. API's built on top of this interface may want to provide - * finer grained access control to the contents of individual - * instrumentation objects contained within the buffer. - *

- * Please note that the "sun.misc.Perf.getPerf" permission - * is not a JDK specified permission. - * - * @return A reference to the singleton Perf instance. - * @throws AccessControlException if a security manager exists and - * its checkPermission method doesn't allow - * access to the "sun.misc.Perf.getPerf" target. - * @see java.lang.RuntimePermission - * @see #attach - */ - public static Perf getPerf() - { - SecurityManager security = System.getSecurityManager(); - if (security != null) { - Permission perm = new RuntimePermission("sun.misc.Perf.getPerf"); - security.checkPermission(perm); - } - - return instance; - } - - /** - * Attach to the instrumentation buffer for the specified Java virtual - * machine. - *

- * This method will attach to the instrumentation buffer for the - * specified virtual machine. It returns a ByteBuffer object - * that is initialized to access the instrumentation buffer for the - * indicated Java virtual machine. The lvmid parameter is - * a integer value that uniquely identifies the target local Java virtual - * machine. It is typically, but not necessarily, the process id of - * the target Java virtual machine. - *

- * If the lvmid identifies a Java virtual machine different - * from the one running this method, then the coherency characteristics - * of the buffer are implementation dependent. Implementations that do - * not support named, coherent, shared memory may return a - * ByteBuffer object that contains only a snap shot of the - * data in the instrumentation buffer. Implementations that support named, - * coherent, shared memory, may return a ByteBuffer object - * that will be changing dynamically over time as the target Java virtual - * machine updates its mapping of this buffer. - *

- * If the lvmid is 0 or equal to the actual lvmid - * for the Java virtual machine running this method, then the returned - * ByteBuffer object will always be coherent and dynamically - * changing. - *

- * The attach mode specifies the access permissions requested for the - * instrumentation buffer of the target virtual machine. The permitted - * access permissions are: - *

    - *
  • "r" - Read only access. This Java virtual machine has only - * read access to the instrumentation buffer for the target Java - * virtual machine. - *
  • "rw" - Read/Write access. This Java virtual machine has read and - * write access to the instrumentation buffer for the target Java virtual - * machine. This mode is currently not supported and is reserved for - * future enhancements. - *
- * - * @param lvmid an integer that uniquely identifies the - * target local Java virtual machine. - * @param mode a string indicating the attach mode. - * @return ByteBuffer a direct allocated byte buffer - * @throws IllegalArgumentException The lvmid or mode was invalid. - * @throws IOException An I/O error occurred while trying to acquire - * the instrumentation buffer. - * @throws OutOfMemoryError The instrumentation buffer could not be mapped - * into the virtual machine's address space. - * @see java.nio.ByteBuffer - */ - public ByteBuffer attach(int lvmid, String mode) - throws IllegalArgumentException, IOException - { - if (mode.compareTo("r") == 0) { - return attachImpl(null, lvmid, PERF_MODE_RO); - } - else if (mode.compareTo("rw") == 0) { - return attachImpl(null, lvmid, PERF_MODE_RW); - } - else { - throw new IllegalArgumentException("unknown mode"); - } - } - - /** - * Attach to the instrumentation buffer for the specified Java virtual - * machine owned by the given user. - *

- * This method behaves just as the attach(int lvmid, String mode) - * method, except that it only searches for Java virtual machines - * owned by the specified user. - * - * @param user A String object containing the - * name of the user that owns the target Java - * virtual machine. - * @param lvmid an integer that uniquely identifies the - * target local Java virtual machine. - * @param mode a string indicating the attach mode. - * @return ByteBuffer a direct allocated byte buffer - * @throws IllegalArgumentException The lvmid or mode was invalid. - * @throws IOException An I/O error occurred while trying to acquire - * the instrumentation buffer. - * @throws OutOfMemoryError The instrumentation buffer could not be mapped - * into the virtual machine's address space. - * @see java.nio.ByteBuffer - */ - public ByteBuffer attach(String user, int lvmid, String mode) - throws IllegalArgumentException, IOException - { - if (mode.compareTo("r") == 0) { - return attachImpl(user, lvmid, PERF_MODE_RO); - } - else if (mode.compareTo("rw") == 0) { - return attachImpl(user, lvmid, PERF_MODE_RW); - } - else { - throw new IllegalArgumentException("unknown mode"); - } - } - - /** - * Call the implementation specific attach method. - *

- * This method calls into the Java virtual machine to perform the platform - * specific attach method. Buffers returned from this method are - * internally managed as PhantomRefereces to provide for - * guaranteed, secure release of the native resources. - * - * @param user A String object containing the - * name of the user that owns the target Java - * virtual machine. - * @param lvmid an integer that uniquely identifies the - * target local Java virtual machine. - * @param mode a string indicating the attach mode. - * @return ByteBuffer a direct allocated byte buffer - * @throws IllegalArgumentException The lvmid or mode was invalid. - * @throws IOException An I/O error occurred while trying to acquire - * the instrumentation buffer. - * @throws OutOfMemoryError The instrumentation buffer could not be mapped - * into the virtual machine's address space. - */ - private ByteBuffer attachImpl(String user, int lvmid, int mode) - throws IllegalArgumentException, IOException - { - final ByteBuffer b = attach(user, lvmid, mode); - - if (lvmid == 0) { - // The native instrumentation buffer for this Java virtual - // machine is never unmapped. - return b; - } - else { - // This is an instrumentation buffer for another Java virtual - // machine with native resources that need to be managed. We - // create a duplicate of the native ByteBuffer and manage it - // with a Cleaner object (PhantomReference). When the duplicate - // becomes only phantomly reachable, the native resources will - // be released. - - final ByteBuffer dup = b.duplicate(); - Cleaner.create(dup, new Runnable() { - public void run() { - try { - instance.detach(b); - } - catch (Throwable th) { - // avoid crashing the reference handler thread, - // but provide for some diagnosability - assert false : th.toString(); - } - } - }); - return dup; - } - } - - /** - * Native method to perform the implementation specific attach mechanism. - *

- * The implementation of this method may return distinct or identical - * ByteBuffer objects for two distinct calls requesting - * attachment to the same Java virtual machine. - *

- * For the Sun HotSpot JVM, two distinct calls to attach to the same - * target Java virtual machine will result in two distinct ByteBuffer - * objects returned by this method. This may change in a future release. - * - * @param user A String object containing the - * name of the user that owns the target Java - * virtual machine. - * @param lvmid an integer that uniquely identifies the - * target local Java virtual machine. - * @param mode a string indicating the attach mode. - * @return ByteBuffer a direct allocated byte buffer - * @throws IllegalArgumentException The lvmid or mode was invalid. - * @throws IOException An I/O error occurred while trying to acquire - * the instrumentation buffer. - * @throws OutOfMemoryError The instrumentation buffer could not be mapped - * into the virtual machine's address space. - */ - private native ByteBuffer attach(String user, int lvmid, int mode) - throws IllegalArgumentException, IOException; - - /** - * Native method to perform the implementation specific detach mechanism. - *

- * If this method is passed a ByteBuffer object that is - * not created by the attach method, then the results of - * this method are undefined, with unpredictable and potentially damaging - * effects to the Java virtual machine. To prevent accidental or malicious - * use of this method, all native ByteBuffer created by the - * attach method are managed internally as PhantomReferences - * and resources are freed by the system. - *

- * If this method is passed a ByteBuffer object created - * by the attach method with a lvmid for the Java virtual - * machine running this method (lvmid=0, for example), then the detach - * request is silently ignored. - * - * @param ByteBuffer A direct allocated byte buffer created by the - * attach method. - * @see java.nio.ByteBuffer - * @see #attach - */ - private native void detach(ByteBuffer bb); - - /** - * Create a long scalar entry in the instrumentation buffer - * with the given variability characteristic, units, and initial value. - *

- * Access to the instrument is provided through the returned - * ByteBuffer object. Typically, this object should be wrapped - * with LongBuffer view object. - * - * @param variability the variability characteristic for this entry. - * @param units the units for this entry. - * @param name the name of this entry. - * @param value the initial value for this entry. - * @return ByteBuffer a direct allocated ByteBuffer object that - * allows write access to a native memory location - * containing a long value. - * - * see sun.misc.perf.Variability - * see sun.misc.perf.Units - * @see java.nio.ByteBuffer - */ - public native ByteBuffer createLong(String name, int variability, - int units, long value); - - /** - * Create a String entry in the instrumentation buffer with - * the given variability characteristic, units, and initial value. - *

- * The maximum length of the String stored in this string - * instrument is given in by maxLength parameter. Updates - * to this instrument with String values with lengths greater - * than maxLength will be truncated to maxLength. - * The truncated value will be terminated by a null character. - *

- * The underlying implementation may further limit the length of the - * value, but will continue to preserve the null terminator. - *

- * Access to the instrument is provided through the returned - * ByteBuffer object. - * - * @param variability the variability characteristic for this entry. - * @param units the units for this entry. - * @param name the name of this entry. - * @param value the initial value for this entry. - * @param maxLength the maximum string length for this string - * instrument. - * @return ByteBuffer a direct allocated ByteBuffer that allows - * write access to a native memory location - * containing a long value. - * - * see sun.misc.perf.Variability - * see sun.misc.perf.Units - * @see java.nio.ByteBuffer - */ - public ByteBuffer createString(String name, int variability, - int units, String value, int maxLength) - { - byte[] v = getBytes(value); - byte[] v1 = new byte[v.length+1]; - System.arraycopy(v, 0, v1, 0, v.length); - v1[v.length] = '\0'; - return createByteArray(name, variability, units, v1, Math.max(v1.length, maxLength)); - } - - /** - * Create a String entry in the instrumentation buffer with - * the given variability characteristic, units, and initial value. - *

- * The maximum length of the String stored in this string - * instrument is implied by the length of the value parameter. - * Subsequent updates to the value of this instrument will be truncated - * to this implied maximum length. The truncated value will be terminated - * by a null character. - *

- * The underlying implementation may further limit the length of the - * initial or subsequent value, but will continue to preserve the null - * terminator. - *

- * Access to the instrument is provided through the returned - * ByteBuffer object. - * - * @param variability the variability characteristic for this entry. - * @param units the units for this entry. - * @param name the name of this entry. - * @param value the initial value for this entry. - * @return ByteBuffer a direct allocated ByteBuffer that allows - * write access to a native memory location - * containing a long value. - * - * see sun.misc.perf.Variability - * see sun.misc.perf.Units - * @see java.nio.ByteBuffer - */ - public ByteBuffer createString(String name, int variability, - int units, String value) - { - byte[] v = getBytes(value); - byte[] v1 = new byte[v.length+1]; - System.arraycopy(v, 0, v1, 0, v.length); - v1[v.length] = '\0'; - return createByteArray(name, variability, units, v1, v1.length); - } - - /** - * Create a byte vector entry in the instrumentation buffer - * with the given variability characteristic, units, and initial value. - *

- * The maxLength parameter limits the size of the byte - * array instrument such that the initial or subsequent updates beyond - * this length are silently ignored. No special handling of truncated - * updates is provided. - *

- * The underlying implementation may further limit the length of the - * length of the initial or subsequent value. - *

- * Access to the instrument is provided through the returned - * ByteBuffer object. - * - * @param variability the variability characteristic for this entry. - * @param units the units for this entry. - * @param name the name of this entry. - * @param value the initial value for this entry. - * @param maxLength the maximum length of this byte array. - * @return ByteBuffer a direct allocated byte buffer that allows - * write access to a native memory location - * containing a long value. - * - * see sun.misc.perf.Variability - * see sun.misc.perf.Units - * @see java.nio.ByteBuffer - */ - public native ByteBuffer createByteArray(String name, int variability, - int units, byte[] value, - int maxLength); - - - /** - * convert string to an array of UTF-8 bytes - */ - private static byte[] getBytes(String s) - { - byte[] bytes = null; - - try { - bytes = s.getBytes("UTF-8"); - } - catch (UnsupportedEncodingException e) { - // ignore, UTF-8 encoding is always known - } - - return bytes; - } - - /** - * Return the value of the High Resolution Counter. - * - * The High Resolution Counter returns the number of ticks since - * since the start of the Java virtual machine. The resolution of - * the counter is machine dependent and can be determined from the - * value return by the {@link #highResFrequency} method. - * - * @return the number of ticks of machine dependent resolution since - * the start of the Java virtual machine. - * - * @see #highResFrequency - * @see java.lang.System#currentTimeMillis() - */ - public native long highResCounter(); - - /** - * Returns the frequency of the High Resolution Counter, in ticks per - * second. - * - * This value can be used to convert the value of the High Resolution - * Counter, as returned from a call to the {@link #highResCounter} method, - * into the number of seconds since the start of the Java virtual machine. - * - * @return the frequency of the High Resolution Counter. - * @see #highResCounter - */ - public native long highResFrequency(); - - private static native void registerNatives(); - - static { - registerNatives(); - instance = new Perf(); - } -} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/misc/PerfCounter.java --- a/jdk/src/java.base/share/classes/sun/misc/PerfCounter.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.LongBuffer; -import java.security.AccessController; - -/** - * Performance counter support for internal JRE classes. - * This class defines a fixed list of counters for the platform - * to use as an interim solution until RFE# 6209222 is implemented. - * The perf counters will be created in the jvmstat perf buffer - * that the HotSpot VM creates. The default size is 32K and thus - * the number of counters is bounded. You can alter the size - * with {@code -XX:PerfDataMemorySize=} option. If there is - * insufficient memory in the jvmstat perf buffer, the C heap memory - * will be used and thus the application will continue to run if - * the counters added exceeds the buffer size but the counters - * will be missing. - * - * See HotSpot jvmstat implementation for certain circumstances - * that the jvmstat perf buffer is not supported. - * - */ -public class PerfCounter { - private static final Perf perf = - AccessController.doPrivileged(new Perf.GetPerfAction()); - - // Must match values defined in hotspot/src/share/vm/runtime/perfdata.hpp - private static final int V_Constant = 1; - private static final int V_Monotonic = 2; - private static final int V_Variable = 3; - private static final int U_None = 1; - - private final String name; - private final LongBuffer lb; - - private PerfCounter(String name, int type) { - this.name = name; - ByteBuffer bb = perf.createLong(name, type, U_None, 0L); - bb.order(ByteOrder.nativeOrder()); - this.lb = bb.asLongBuffer(); - } - - static PerfCounter newPerfCounter(String name) { - return new PerfCounter(name, V_Variable); - } - - static PerfCounter newConstantPerfCounter(String name) { - PerfCounter c = new PerfCounter(name, V_Constant); - return c; - } - - /** - * Returns the current value of the perf counter. - */ - public synchronized long get() { - return lb.get(0); - } - - /** - * Sets the value of the perf counter to the given newValue. - */ - public synchronized void set(long newValue) { - lb.put(0, newValue); - } - - /** - * Adds the given value to the perf counter. - */ - public synchronized void add(long value) { - long res = get() + value; - lb.put(0, res); - } - - /** - * Increments the perf counter with 1. - */ - public void increment() { - add(1); - } - - /** - * Adds the given interval to the perf counter. - */ - public void addTime(long interval) { - add(interval); - } - - /** - * Adds the elapsed time from the given start time (ns) to the perf counter. - */ - public void addElapsedTimeFrom(long startTime) { - add(System.nanoTime() - startTime); - } - - @Override - public String toString() { - return name + " = " + get(); - } - - static class CoreCounters { - static final PerfCounter pdt = newPerfCounter("sun.classloader.parentDelegationTime"); - static final PerfCounter lc = newPerfCounter("sun.classloader.findClasses"); - static final PerfCounter lct = newPerfCounter("sun.classloader.findClassTime"); - static final PerfCounter rcbt = newPerfCounter("sun.urlClassLoader.readClassBytesTime"); - static final PerfCounter zfc = newPerfCounter("sun.zip.zipFiles"); - static final PerfCounter zfot = newPerfCounter("sun.zip.zipFile.openTime"); - } - - static class WindowsClientCounters { - static final PerfCounter d3dAvailable = newConstantPerfCounter("sun.java2d.d3d.available"); - } - - /** - * Number of findClass calls - */ - public static PerfCounter getFindClasses() { - return CoreCounters.lc; - } - - /** - * Time (ns) spent in finding classes that includes - * lookup and read class bytes and defineClass - */ - public static PerfCounter getFindClassTime() { - return CoreCounters.lct; - } - - /** - * Time (ns) spent in finding classes - */ - public static PerfCounter getReadClassBytesTime() { - return CoreCounters.rcbt; - } - - /** - * Time (ns) spent in the parent delegation to - * the parent of the defining class loader - */ - public static PerfCounter getParentDelegationTime() { - return CoreCounters.pdt; - } - - /** - * Number of zip files opened. - */ - public static PerfCounter getZipFileCount() { - return CoreCounters.zfc; - } - - /** - * Time (ns) spent in opening the zip files that - * includes building the entries hash table - */ - public static PerfCounter getZipFileOpenTime() { - return CoreCounters.zfot; - } - - /** - * D3D graphic pipeline available - */ - public static PerfCounter getD3DAvailable() { - return WindowsClientCounters.d3dAvailable; - } -} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/misc/PerformanceLogger.java --- a/jdk/src/java.base/share/classes/sun/misc/PerformanceLogger.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,317 +0,0 @@ -/* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - - -package sun.misc; - -import java.util.Vector; -import java.io.FileWriter; -import java.io.File; -import java.io.OutputStreamWriter; -import java.io.Writer; - -/** - * This class is intended to be a central place for the jdk to - * log timing events of interest. There is pre-defined event - * of startTime, as well as a general - * mechanism of setting arbitrary times in an array. - * All unreserved times in the array can be used by callers - * in application-defined situations. The caller is responsible - * for setting and getting all times and for doing whatever - * analysis is interesting; this class is merely a central container - * for those timing values. - * Note that, due to the variables in this class being static, - * use of particular time values by multiple applets will cause - * confusing results. For example, if plugin runs two applets - * simultaneously, the initTime for those applets will collide - * and the results may be undefined. - *

- * To automatically track startup performance in an app or applet, - * use the command-line parameter sun.perflog as follows:
- *

{@code
- *     -Dsun.perflog[=file:]
- * }
- *
- * where simply using the parameter with no value will enable output - * to the console and a value of "{@code file:}" will cause - * that given filename to be created and used for all output. - *

- * By default, times are measured using System.currentTimeMillis(). To use - * System.nanoTime() instead, add the command-line parameter:
- -Dsun.perflog.nano=true - *
- *

- * Warning: Use at your own risk! - * This class is intended for internal testing - * purposes only and may be removed at any time. More - * permanent monitoring and profiling APIs are expected to be - * developed for future releases and this class will cease to - * exist once those APIs are in place. - * @author Chet Haase - */ -public class PerformanceLogger { - - // Timing values of global interest - private static final int START_INDEX = 0; // VM start - private static final int LAST_RESERVED = START_INDEX; - - private static boolean perfLoggingOn = false; - private static boolean useNanoTime = false; - private static Vector times; - private static String logFileName = null; - private static Writer logWriter = null; - private static long baseTime; - - static { - String perfLoggingProp = - java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.perflog")); - if (perfLoggingProp != null) { - perfLoggingOn = true; - - // Check if we should use nanoTime - String perfNanoProp = - java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("sun.perflog.nano")); - if (perfNanoProp != null) { - useNanoTime = true; - } - - // Now, figure out what the user wants to do with the data - if (perfLoggingProp.regionMatches(true, 0, "file:", 0, 5)) { - logFileName = perfLoggingProp.substring(5); - } - if (logFileName != null) { - if (logWriter == null) { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Void run() { - try { - File logFile = new File(logFileName); - logFile.createNewFile(); - logWriter = new FileWriter(logFile); - } catch (Exception e) { - System.out.println(e + ": Creating logfile " + - logFileName + - ". Log to console"); - } - return null; - } - }); - } - } - if (logWriter == null) { - logWriter = new OutputStreamWriter(System.out); - } - } - times = new Vector(10); - // Reserve predefined slots - for (int i = 0; i <= LAST_RESERVED; ++i) { - times.add(new TimeData("Time " + i + " not set", 0)); - } - } - - /** - * Returns status of whether logging is enabled or not. This is - * provided as a convenience method so that users do not have to - * perform the same GetPropertyAction check as above to determine whether - * to enable performance logging. - */ - public static boolean loggingEnabled() { - return perfLoggingOn; - } - - - /** - * Internal class used to store time/message data together. - */ - static class TimeData { - String message; - long time; - - TimeData(String message, long time) { - this.message = message; - this.time = time; - } - - String getMessage() { - return message; - } - - long getTime() { - return time; - } - } - - /** - * Return the current time, in millis or nanos as appropriate - */ - private static long getCurrentTime() { - if (useNanoTime) { - return System.nanoTime(); - } else { - return System.currentTimeMillis(); - } - } - - /** - * Sets the start time. Ideally, this is the earliest time available - * during the startup of a Java applet or application. This time is - * later used to analyze the difference between the initial startup - * time and other events in the system (such as an applet's init time). - */ - public static void setStartTime(String message) { - if (loggingEnabled()) { - long nowTime = getCurrentTime(); - setStartTime(message, nowTime); - } - } - - /** - * Sets the base time, output can then - * be displayed as offsets from the base time;. - */ - public static void setBaseTime(long time) { - if (loggingEnabled()) { - baseTime = time; - } - } - - /** - * Sets the start time. - * This version of the method is - * given the time to log, instead of expecting this method to - * get the time itself. This is done in case the time was - * recorded much earlier than this method was called. - */ - public static void setStartTime(String message, long time) { - if (loggingEnabled()) { - times.set(START_INDEX, new TimeData(message, time)); - } - } - - /** - * Gets the start time, which should be the time when - * the java process started, prior to the VM actually being - * loaded. - */ - public static long getStartTime() { - if (loggingEnabled()) { - return times.get(START_INDEX).getTime(); - } else { - return 0; - } - } - - /** - * Sets the value of a given time and returns the index of the - * slot that that time was stored in. - */ - public static int setTime(String message) { - if (loggingEnabled()) { - long nowTime = getCurrentTime(); - return setTime(message, nowTime); - } else { - return 0; - } - } - - /** - * Sets the value of a given time and returns the index of the - * slot that that time was stored in. - * This version of the method is - * given the time to log, instead of expecting this method to - * get the time itself. This is done in case the time was - * recorded much earlier than this method was called. - */ - public static int setTime(String message, long time) { - if (loggingEnabled()) { - // times is already synchronized, but we need to ensure that - // the size used in times.set() is the same used when returning - // the index of that operation. - synchronized (times) { - times.add(new TimeData(message, time)); - return (times.size() - 1); - } - } else { - return 0; - } - } - - /** - * Returns time at given index. - */ - public static long getTimeAtIndex(int index) { - if (loggingEnabled()) { - return times.get(index).getTime(); - } else { - return 0; - } - } - - /** - * Returns message at given index. - */ - public static String getMessageAtIndex(int index) { - if (loggingEnabled()) { - return times.get(index).getMessage(); - } else { - return null; - } - } - - /** - * Outputs all data to parameter-specified Writer object - */ - public static void outputLog(Writer writer) { - if (loggingEnabled()) { - try { - synchronized(times) { - for (int i = 0; i < times.size(); ++i) { - TimeData td = times.get(i); - if (td != null) { - writer.write(i + " " + td.getMessage() + ": " + - (td.getTime() - baseTime) + "\n"); - - } - } - } - writer.flush(); - } catch (Exception e) { - System.out.println(e + ": Writing performance log to " + - writer); - } - } - } - - /** - * Outputs all data to whatever location the user specified - * via sun.perflog command-line parameter. - */ - public static void outputLog() { - outputLog(logWriter); - } -} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java --- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -967,12 +967,6 @@ return ""; } - @Override - protected void finalize() throws Throwable { - // This should do nothing. The stream finalizer will - // close the fd. - } - public void setDoNotRetry(boolean value) { // failedOnce is used to determine if a request should be retried. failedOnce = value; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,13 +108,6 @@ return false; } - /* - * close the jar file. - */ - protected void finalize() throws IOException { - close(); - } - /** * Returns the ZipEntry for the given entry name or * null if not found. diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -2211,7 +2211,7 @@ @Override public synchronized String getHandshakeApplicationProtocol() { - if ((handshaker != null) && !handshaker.started()) { + if ((handshaker != null) && handshaker.started()) { return handshaker.getHandshakeApplicationProtocol(); } return null; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -2598,7 +2598,7 @@ @Override public synchronized String getHandshakeApplicationProtocol() { - if ((handshaker != null) && !handshaker.started()) { + if ((handshaker != null) && handshaker.started()) { return handshaker.getHandshakeApplicationProtocol(); } return null; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,13 +153,11 @@ getSupportedAlgorithms(AlgorithmConstraints constraints) { Collection supported = new ArrayList<>(); - synchronized (priorityMap) { - for (SignatureAndHashAlgorithm sigAlg : priorityMap.values()) { - if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - sigAlg.algorithm, null)) { - supported.add(sigAlg); - } + for (SignatureAndHashAlgorithm sigAlg : priorityMap.values()) { + if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM && + constraints.permits(SIGNATURE_PRIMITIVE_SET, + sigAlg.algorithm, null)) { + supported.add(sigAlg); } } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/share/conf/security/java.policy --- a/jdk/src/java.base/share/conf/security/java.policy Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/share/conf/security/java.policy Wed Jul 05 21:13:10 2017 +0200 @@ -98,17 +98,6 @@ // default permissions granted to all domains grant { - // Allows any thread to stop itself using the java.lang.Thread.stop() - // method that takes no argument. - // Note that this permission is granted by default only to remain - // backwards compatible. - // It is strongly recommended that you either remove this permission - // from this policy file or further restrict it to code sources - // that you specify, because Thread.stop() is potentially unsafe. - // See the API specification of java.lang.Thread.stop() for more - // information. - permission java.lang.RuntimePermission "stopThread"; - // allows anyone to listen on dynamic ports permission java.net.SocketPermission "localhost:0", "listen"; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java --- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -47,6 +47,9 @@ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { super.setOption(name, value); } else { + if (!flowSupported()) { + throw new UnsupportedOperationException("unsupported option"); + } if (isClosed()) { throw new SocketException("Socket closed"); } @@ -61,6 +64,9 @@ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { return super.getOption(name); } + if (!flowSupported()) { + throw new UnsupportedOperationException("unsupported option"); + } if (isClosed()) { throw new SocketException("Socket closed"); } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java --- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -61,6 +61,9 @@ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { super.setOption(name, value); } else { + if (getSocket() == null || !flowSupported()) { + throw new UnsupportedOperationException("unsupported option"); + } if (isClosedOrPending()) { throw new SocketException("Socket closed"); } @@ -75,6 +78,9 @@ if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { return super.getOption(name); } + if (getSocket() == null || !flowSupported()) { + throw new UnsupportedOperationException("unsupported option"); + } if (isClosedOrPending()) { throw new SocketException("Socket closed"); } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java --- a/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -42,8 +42,10 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; + import jdk.internal.misc.JavaIOFileDescriptorAccess; import jdk.internal.misc.SharedSecrets; +import jdk.internal.ref.CleanerFactory; /* This class is for the exclusive use of ProcessBuilder.start() to * create new processes. @@ -417,6 +419,10 @@ handle = create(cmdstr, envblock, path, stdHandles, redirectErrorStream); + // Register a cleaning function to close the handle + final long local_handle = handle; // local to prevent capture of this + CleanerFactory.cleaner().register(this, () -> closeHandle(local_handle)); + processHandle = ProcessHandleImpl.getInternal(getProcessId0(handle)); java.security.AccessController.doPrivileged( @@ -463,10 +469,6 @@ return stderr_stream; } - protected void finalize() { - closeHandle(handle); - } - private static final int STILL_ACTIVE = getStillActive(); private static native int getStillActive(); diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/windows/native/libjli/java_md.c --- a/jdk/src/java.base/windows/native/libjli/java_md.c Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/windows/native/libjli/java_md.c Wed Jul 05 21:13:10 2017 +0200 @@ -337,6 +337,15 @@ } } + /* Try getting path to JRE from path to JLI.DLL */ + if (GetApplicationHomeFromDll(path, pathsize)) { + JLI_Snprintf(javadll, sizeof(javadll), "%s\\bin\\" JAVA_DLL, path); + if (stat(javadll, &s) == 0) { + JLI_TraceLauncher("JRE path is %s\n", path); + return JNI_TRUE; + } + } + JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL); return JNI_FALSE; @@ -404,17 +413,17 @@ } /* - * If app is "c:\foo\bin\javac", then put "c:\foo" into buf. + * Removes the trailing file name and one sub-folder from a path. + * If buf is "c:\foo\bin\javac", then put "c:\foo" into buf. */ jboolean -GetApplicationHome(char *buf, jint bufsize) +TruncatePath(char *buf) { char *cp; - GetModuleFileName(0, buf, bufsize); *JLI_StrRChr(buf, '\\') = '\0'; /* remove .exe file name */ if ((cp = JLI_StrRChr(buf, '\\')) == 0) { /* This happens if the application is in a drive root, and - * there is no bin directory. */ + * there is no bin directory. */ buf[0] = '\0'; return JNI_FALSE; } @@ -423,6 +432,36 @@ } /* + * Retrieves the path to the JRE home by locating the executable file + * of the current process and then truncating the path to the executable + */ +jboolean +GetApplicationHome(char *buf, jint bufsize) +{ + GetModuleFileName(NULL, buf, bufsize); + return TruncatePath(buf); +} + +/* + * Retrieves the path to the JRE home by locating JLI.DLL and + * then truncating the path to JLI.DLL + */ +jboolean +GetApplicationHomeFromDll(char *buf, jint bufsize) +{ + HMODULE hModule; + DWORD dwFlags = + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT; + + if (GetModuleHandleEx(dwFlags, (LPCSTR)&GetJREPath, &hModule) == 0) { + return JNI_FALSE; + }; + GetModuleFileName(hModule, buf, bufsize); + return TruncatePath(buf); +} + +/* * Support for doing cheap, accurate interval timing. */ static jboolean counterAvailable = JNI_FALSE; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.base/windows/native/libjli/java_md.h --- a/jdk/src/java.base/windows/native/libjli/java_md.h Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.base/windows/native/libjli/java_md.h Wed Jul 05 21:13:10 2017 +0200 @@ -54,4 +54,7 @@ int UnsetEnv(char *name); +jboolean +GetApplicationHomeFromDll(char *buf, jint bufsize); + #endif /* JAVA_MD_H */ diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java Wed Jul 05 21:13:10 2017 +0200 @@ -43,8 +43,8 @@ import sun.awt.AppContext; import sun.awt.EmbeddedFrame; import sun.awt.SunToolkit; +import sun.awt.util.PerformanceLogger; import sun.misc.ManagedLocalsThread; -import sun.misc.PerformanceLogger; import sun.security.util.SecurityConstants; /** diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.desktop/share/classes/sun/awt/util/PerformanceLogger.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.desktop/share/classes/sun/awt/util/PerformanceLogger.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + + +package sun.awt.util; + +import java.util.Vector; +import java.io.FileWriter; +import java.io.File; +import java.io.OutputStreamWriter; +import java.io.Writer; + +/** + * This class is intended to be a central place for the jdk to + * log timing events of interest. There is pre-defined event + * of startTime, as well as a general + * mechanism of setting arbitrary times in an array. + * All unreserved times in the array can be used by callers + * in application-defined situations. The caller is responsible + * for setting and getting all times and for doing whatever + * analysis is interesting; this class is merely a central container + * for those timing values. + * Note that, due to the variables in this class being static, + * use of particular time values by multiple applets will cause + * confusing results. For example, if plugin runs two applets + * simultaneously, the initTime for those applets will collide + * and the results may be undefined. + *

+ * To automatically track startup performance in an app or applet, + * use the command-line parameter sun.perflog as follows:
+ *

{@code
+ *     -Dsun.perflog[=file:]
+ * }
+ *
+ * where simply using the parameter with no value will enable output + * to the console and a value of "{@code file:}" will cause + * that given filename to be created and used for all output. + *

+ * By default, times are measured using System.currentTimeMillis(). To use + * System.nanoTime() instead, add the command-line parameter:
+ -Dsun.perflog.nano=true + *
+ *

+ * Warning: Use at your own risk! + * This class is intended for internal testing + * purposes only and may be removed at any time. More + * permanent monitoring and profiling APIs are expected to be + * developed for future releases and this class will cease to + * exist once those APIs are in place. + * @author Chet Haase + */ +public class PerformanceLogger { + + // Timing values of global interest + private static final int START_INDEX = 0; // VM start + private static final int LAST_RESERVED = START_INDEX; + + private static boolean perfLoggingOn = false; + private static boolean useNanoTime = false; + private static Vector times; + private static String logFileName = null; + private static Writer logWriter = null; + private static long baseTime; + + static { + String perfLoggingProp = + java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("sun.perflog")); + if (perfLoggingProp != null) { + perfLoggingOn = true; + + // Check if we should use nanoTime + String perfNanoProp = + java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("sun.perflog.nano")); + if (perfNanoProp != null) { + useNanoTime = true; + } + + // Now, figure out what the user wants to do with the data + if (perfLoggingProp.regionMatches(true, 0, "file:", 0, 5)) { + logFileName = perfLoggingProp.substring(5); + } + if (logFileName != null) { + if (logWriter == null) { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + try { + File logFile = new File(logFileName); + logFile.createNewFile(); + logWriter = new FileWriter(logFile); + } catch (Exception e) { + System.out.println(e + ": Creating logfile " + + logFileName + + ". Log to console"); + } + return null; + } + }); + } + } + if (logWriter == null) { + logWriter = new OutputStreamWriter(System.out); + } + } + times = new Vector(10); + // Reserve predefined slots + for (int i = 0; i <= LAST_RESERVED; ++i) { + times.add(new TimeData("Time " + i + " not set", 0)); + } + } + + /** + * Returns status of whether logging is enabled or not. This is + * provided as a convenience method so that users do not have to + * perform the same GetPropertyAction check as above to determine whether + * to enable performance logging. + */ + public static boolean loggingEnabled() { + return perfLoggingOn; + } + + + /** + * Internal class used to store time/message data together. + */ + static class TimeData { + String message; + long time; + + TimeData(String message, long time) { + this.message = message; + this.time = time; + } + + String getMessage() { + return message; + } + + long getTime() { + return time; + } + } + + /** + * Return the current time, in millis or nanos as appropriate + */ + private static long getCurrentTime() { + if (useNanoTime) { + return System.nanoTime(); + } else { + return System.currentTimeMillis(); + } + } + + /** + * Sets the start time. Ideally, this is the earliest time available + * during the startup of a Java applet or application. This time is + * later used to analyze the difference between the initial startup + * time and other events in the system (such as an applet's init time). + */ + public static void setStartTime(String message) { + if (loggingEnabled()) { + long nowTime = getCurrentTime(); + setStartTime(message, nowTime); + } + } + + /** + * Sets the base time, output can then + * be displayed as offsets from the base time;. + */ + public static void setBaseTime(long time) { + if (loggingEnabled()) { + baseTime = time; + } + } + + /** + * Sets the start time. + * This version of the method is + * given the time to log, instead of expecting this method to + * get the time itself. This is done in case the time was + * recorded much earlier than this method was called. + */ + public static void setStartTime(String message, long time) { + if (loggingEnabled()) { + times.set(START_INDEX, new TimeData(message, time)); + } + } + + /** + * Gets the start time, which should be the time when + * the java process started, prior to the VM actually being + * loaded. + */ + public static long getStartTime() { + if (loggingEnabled()) { + return times.get(START_INDEX).getTime(); + } else { + return 0; + } + } + + /** + * Sets the value of a given time and returns the index of the + * slot that that time was stored in. + */ + public static int setTime(String message) { + if (loggingEnabled()) { + long nowTime = getCurrentTime(); + return setTime(message, nowTime); + } else { + return 0; + } + } + + /** + * Sets the value of a given time and returns the index of the + * slot that that time was stored in. + * This version of the method is + * given the time to log, instead of expecting this method to + * get the time itself. This is done in case the time was + * recorded much earlier than this method was called. + */ + public static int setTime(String message, long time) { + if (loggingEnabled()) { + // times is already synchronized, but we need to ensure that + // the size used in times.set() is the same used when returning + // the index of that operation. + synchronized (times) { + times.add(new TimeData(message, time)); + return (times.size() - 1); + } + } else { + return 0; + } + } + + /** + * Returns time at given index. + */ + public static long getTimeAtIndex(int index) { + if (loggingEnabled()) { + return times.get(index).getTime(); + } else { + return 0; + } + } + + /** + * Returns message at given index. + */ + public static String getMessageAtIndex(int index) { + if (loggingEnabled()) { + return times.get(index).getMessage(); + } else { + return null; + } + } + + /** + * Outputs all data to parameter-specified Writer object + */ + public static void outputLog(Writer writer) { + if (loggingEnabled()) { + try { + synchronized(times) { + for (int i = 0; i < times.size(); ++i) { + TimeData td = times.get(i); + if (td != null) { + writer.write(i + " " + td.getMessage() + ": " + + (td.getTime() - baseTime) + "\n"); + + } + } + } + writer.flush(); + } catch (Exception e) { + System.out.println(e + ": Writing performance log to " + + writer); + } + } + } + + /** + * Outputs all data to whatever location the user specified + * via sun.perflog command-line parameter. + */ + public static void outputLog() { + outputLog(logWriter); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java --- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java Wed Jul 05 21:13:10 2017 +0200 @@ -88,9 +88,9 @@ import sun.java2d.loops.XORComposite; import sun.awt.ConstrainableGraphics; import sun.awt.SunHints; +import sun.awt.util.PerformanceLogger; import java.util.Map; import java.util.Iterator; -import sun.misc.PerformanceLogger; import java.lang.annotation.Native; import java.awt.image.MultiResolutionImage; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Wed Jul 05 21:13:10 2017 +0200 @@ -52,6 +52,7 @@ import sun.font.FontConfigManager; import sun.java2d.SunGraphicsEnvironment; import sun.misc.*; +import sun.awt.util.PerformanceLogger; import sun.awt.util.ThreadGroupUtils; import sun.print.PrintJob2D; import sun.security.action.GetPropertyAction; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java Wed Jul 05 21:13:10 2017 +0200 @@ -67,10 +67,10 @@ import java.util.Map; import java.util.Properties; +import sun.awt.util.PerformanceLogger; import sun.font.FontManager; import sun.font.FontManagerFactory; import sun.font.SunFontManager; -import sun.misc.PerformanceLogger; import sun.util.logging.PlatformLogger; public final class WToolkit extends SunToolkit implements Runnable { diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsDevice.java Wed Jul 05 21:13:10 2017 +0200 @@ -38,6 +38,7 @@ import java.awt.peer.WindowPeer; import java.util.ArrayList; +import jdk.internal.perf.PerfCounter; import sun.awt.AWTAccessor; import sun.awt.AWTAccessor.ComponentAccessor; import sun.awt.Win32GraphicsDevice; @@ -69,9 +70,9 @@ if (d3dAvailable) { // we don't use pixel formats for the d3d pipeline pfDisabled = true; - sun.misc.PerfCounter.getD3DAvailable().set(1); + PerfCounter.getD3DAvailable().set(1); } else { - sun.misc.PerfCounter.getD3DAvailable().set(0); + PerfCounter.getD3DAvailable().set(0); } } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.management/share/classes/sun/management/ConnectorAddressLink.java --- a/jdk/src/java.management/share/classes/sun/management/ConnectorAddressLink.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.management/share/classes/sun/management/ConnectorAddressLink.java Wed Jul 05 21:13:10 2017 +0200 @@ -34,7 +34,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import sun.misc.Perf; +import jdk.internal.perf.Perf; import sun.management.counter.Units; import sun.management.counter.Counter; import sun.management.counter.perf.PerfInstrumentation; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.management/share/classes/sun/management/VMManagementImpl.java --- a/jdk/src/java.management/share/classes/sun/management/VMManagementImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.management/share/classes/sun/management/VMManagementImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -25,7 +25,7 @@ package sun.management; -import sun.misc.Perf; +import jdk.internal.perf.Perf; import sun.management.counter.*; import sun.management.counter.perf.*; import java.nio.ByteBuffer; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.scripting/share/classes/javax/script/ScriptEngineFactory.java --- a/jdk/src/java.scripting/share/classes/javax/script/ScriptEngineFactory.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.scripting/share/classes/javax/script/ScriptEngineFactory.java Wed Jul 05 21:13:10 2017 +0200 @@ -31,12 +31,14 @@ * ScriptEngineFactory is used to describe and instantiate * ScriptEngines. *

- * Each class implementing ScriptEngine has a corresponding factory - * that exposes metadata describing the engine class. + * Each class implementing ScriptEngine has a corresponding + * factory that exposes metadata describing the engine class. *

The ScriptEngineManager - * uses the service provider mechanism described in the Jar File Specification to obtain - * instances of all ScriptEngineFactories available in - * the current ClassLoader. + * uses the service-provider loader mechanism described in the + * {@link java.util.ServiceLoader} class to obtain + * instances of {@code ScriptEngineFactory} instances. + * See {@link ScriptEngineManager#ScriptEngineManager()} and + * {@link ScriptEngineManager#ScriptEngineManager(java.lang.ClassLoader)}. * * @since 1.6 */ diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.scripting/share/classes/javax/script/ScriptEngineManager.java --- a/jdk/src/java.scripting/share/classes/javax/script/ScriptEngineManager.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/java.scripting/share/classes/javax/script/ScriptEngineManager.java Wed Jul 05 21:13:10 2017 +0200 @@ -33,7 +33,8 @@ * The ScriptEngineManager implements a discovery and instantiation * mechanism for ScriptEngine classes and also maintains a * collection of key/value pairs storing state shared by all engines created - * by the Manager. This class uses the service provider mechanism to enumerate all the + * by the Manager. This class uses the service provider mechanism described in the + * {@link java.util.ServiceLoader} class to enumerate all the * implementations of ScriptEngineFactory.

* The ScriptEngineManager provides a method to return a list of all these factories * as well as utility methods which look up factories on the basis of language name, file extension @@ -64,7 +65,7 @@ /** * This constructor loads the implementations of * ScriptEngineFactory visible to the given - * ClassLoader using the service provider mechanism.

+ * ClassLoader using the service provider mechanism.

* If loader is null, the script engine factories that are * bundled with the platform are loaded.
* diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.scripting/share/classes/javax/script/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.scripting/share/classes/javax/script/package-info.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/** + +

The scripting API consists of interfaces and classes that define +Java™ Scripting Engines and provides +a framework for their use in Java applications. This API is intended +for use by application programmers who wish to execute programs +written in scripting languages in their Java applications. The +scripting language programs are usually provided by the end-users of +the applications. +

+

The main areas of functionality of javax.script +package include +

+
    +
  1. Script execution: Scripts +are streams of characters used as sources for programs executed by +script engines. Script execution uses +{@link javax.script.ScriptEngine#eval eval} methods of +{@link javax.script.ScriptEngine ScriptEngine} and methods of the +{@link javax.script.Invocable Invocable} interface. +

    +
  2. Binding: This facility +allows Java objects to be exposed to script programs as named +variables. {@link javax.script.Bindings Bindings} and +{@link javax.script.ScriptContext ScriptContext} +classes are used for this purpose. +

    +
  3. Compilation: This +functionality allows the intermediate code generated by the +front-end of a script engine to be stored and executed repeatedly. +This benefits applications that execute the same script multiple +times. These applications can gain efficiency since the engines' +front-ends only need to execute once per script rather than once per +script execution. Note that this functionality is optional and +script engines may choose not to implement it. Callers need to check +for availability of the {@link javax.script.Compilable Compilable} +interface using an instanceof check. +

    +
  4. Invocation: This +functionality allows the reuse of intermediate code generated by a +script engine's front-end. Whereas Compilation allows entire scripts +represented by intermediate code to be re-executed, Invocation +functionality allows individual procedures/methods in the scripts to +be re-executed. As in the case with compilation, not all script +engines are required to provide this facility. Caller has to check +for {@link javax.script.Invocable Invocable} availability. +

    +
  5. Script engine discovery: Applications +written to the Scripting API might have specific requirements on +script engines. Some may require a specific scripting language +and/or version while others may require a specific implementation +engine and/or version. Script engines are packaged in a specified +way so that engines can be discovered at runtime and queried for +attributes. The Engine discovery mechanism is based on the service-provider +loading facility described in the {@link java.util.ServiceLoader} class. +{@link javax.script.ScriptEngineManager ScriptEngineManager} +includes +{@link javax.script.ScriptEngineManager#getEngineFactories getEngineFactories} method to get all +{@link javax.script.ScriptEngineFactory ScriptEngineFactory} instances +discovered using this mechanism. ScriptEngineFactory has +methods to query attributes about script engine. +

    +
+ +@since 1.6 +*/ + +package javax.script; + diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/java.scripting/share/classes/javax/script/package.html --- a/jdk/src/java.scripting/share/classes/javax/script/package.html Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ - - - - - - - -

The scripting API consists of interfaces and classes that define -Java™ Scripting Engines and provides -a framework for their use in Java applications. This API is intended -for use by application programmers who wish to execute programs -written in scripting languages in their Java applications. The -scripting language programs are usually provided by the end-users of -the applications. -

-

The main areas of functionality of javax.script -package include -

-
    -
  1. Script execution: Scripts - are streams of characters used as sources for programs executed by - script engines. Script execution uses - {@link javax.script.ScriptEngine#eval eval} methods of - {@link javax.script.ScriptEngine ScriptEngine} and methods of the - {@link javax.script.Invocable Invocable} interface. -

    -
  2. Binding: This facility - allows Java objects to be exposed to script programs as named - variables. {@link javax.script.Bindings Bindings} and - {@link javax.script.ScriptContext ScriptContext} - classes are used for this purpose. -

    -
  3. Compilation: This - functionality allows the intermediate code generated by the - front-end of a script engine to be stored and executed repeatedly. - This benefits applications that execute the same script multiple - times. These applications can gain efficiency since the engines' - front-ends only need to execute once per script rather than once per - script execution. Note that this functionality is optional and - script engines may choose not to implement it. Callers need to check - for availability of the {@link javax.script.Compilable Compilable} - interface using an instanceof check. -

    -
  4. Invocation: This - functionality allows the reuse of intermediate code generated by a - script engine's front-end. Whereas Compilation allows entire scripts - represented by intermediate code to be re-executed, Invocation - functionality allows individual procedures/methods in the scripts to - be re-executed. As in the case with compilation, not all script - engines are required to provide this facility. Caller has to check - for {@link javax.script.Invocable Invocable} availability. -

    -
  5. Script engine discovery and Metadata: Applications - written to the Scripting API might have specific requirements on - script engines. Some may require a specific scripting language - and/or version while others may require a specific implementation - engine and/or version. Script engines are packaged in a specified - way so that engines can be discovered at runtime and queried for - attributes. The Engine discovery mechanism is based on the Service - discovery mechanism described in the Jar File Specification. - Script engine implementing classes are packaged in jar files that - include a text resource named - META-INF/services/javax.script.ScriptEngineFactory. This - resource must include a line for each - {@link javax.script.ScriptEngineFactory ScriptEngineFactory} - that is packaged in the jar file. - {@link javax.script.ScriptEngineManager ScriptEngineManager} - includes - {@link javax.script.ScriptEngineManager#getEngineFactories getEngineFactories} method to get all - {@link javax.script.ScriptEngineFactory ScriptEngineFactory} instances - discovered using this mechanism. ScriptEngineFactory has - methods to query attributes about script engine. -

    -
- -@since 1.6 - - - diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractMonitoredVm.java --- a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractMonitoredVm.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractMonitoredVm.java Wed Jul 05 21:13:10 2017 +0200 @@ -95,7 +95,7 @@ public void detach() { /* * no default action required because the detach operation for the - * native byte buffer is managed by the sun.misc.Perf class. + * native byte buffer is managed by the Perf class. */ } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractPerfDataBuffer.java --- a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractPerfDataBuffer.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/AbstractPerfDataBuffer.java Wed Jul 05 21:13:10 2017 +0200 @@ -25,7 +25,6 @@ package sun.jvmstat.perfdata.monitor; -import sun.misc.Perf; import sun.jvmstat.monitor.*; import java.util.*; import java.io.*; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataBuffer.java --- a/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataBuffer.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata/monitor/protocol/local/PerfDataBuffer.java Wed Jul 05 21:13:10 2017 +0200 @@ -25,7 +25,7 @@ package sun.jvmstat.perfdata.monitor.protocol.local; -import sun.misc.Perf; +import jdk.internal.perf.Perf; import sun.jvmstat.monitor.*; import sun.jvmstat.perfdata.monitor.*; import java.util.*; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/ProblemList.txt Wed Jul 05 21:13:10 2017 +0200 @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -299,6 +299,9 @@ # 8074580 sun/security/pkcs11/rsa/TestKeyPairGenerator.java generic-all +# 8146387 +javax/net/ssl/SSLSession/SessionCacheSizeTests.java windows-all,solaris-all + ############################################################################ # jdk_sound diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/TEST.groups --- a/jdk/test/TEST.groups Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/TEST.groups Wed Jul 05 21:13:10 2017 +0200 @@ -1,4 +1,4 @@ -# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,8 @@ -java/util/zip/TestLocalTime.java \ :jdk_util \ -java/util/WeakHashMap/GCDuringIteration.java \ - -java/util/concurrent/Phaser/Basic.java \ -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java + -java/util/concurrent/forkjoin/FJExceptionTableLeak.java sun/nio/cs/ISO8859x.java \ java/nio/Buffer \ com/sun/crypto/provider/Cipher \ @@ -41,9 +41,9 @@ tier2 = \ java/lang/ProcessHandle/TreeTest.java \ java/util/zip/TestLocalTime.java \ - java/util/concurrent/Phaser/Basic.java \ java/util/WeakHashMap/GCDuringIteration.java \ java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ + java/util/concurrent/forkjoin/FJExceptionTableLeak.java :jdk_io \ :jdk_nio \ -sun/nio/cs/ISO8859x.java \ @@ -77,7 +77,6 @@ sun/misc \ sun/reflect \ jdk/lambda \ - jdk/internal/jimage \ vm # All of the java.util package diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/lang/StackWalker/LocalsAndOperands.java --- a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java Wed Jul 05 21:13:10 2017 +0200 @@ -86,29 +86,43 @@ System.out.println("frame: " + f); Object[] locals = (Object[]) getLocals.invoke(f); for (int i = 0; i < locals.length; i++) { - System.out.format("local %d: %s type %s%n", i, locals[i], type(locals[i])); + System.out.format(" local %d: %s type %s\n", i, locals[i], type(locals[i])); + + // check for non-null locals in LocalsAndOperands.test() + if (f.getClassName().equals("LocalsAndOperands") && + f.getMethodName().equals("test")) { + if (locals[i] == null) { + throw new RuntimeException("kept-alive locals should not be null"); + } + } } Object[] operands = (Object[]) getOperands.invoke(f); for (int i = 0; i < operands.length; i++) { - System.out.format("operand %d: %s type %s%n", i, operands[i], type(operands[i])); + System.out.format(" operand %d: %s type %s%n", i, operands[i], + type(operands[i])); } Object[] monitors = (Object[]) getMonitors.invoke(f); for (int i = 0; i < monitors.length; i++) { - System.out.format("monitor %d: %s%n", i, monitors[i]); + System.out.format(" monitor %d: %s%n", i, monitors[i]); } } } else { for (StackFrame f : frames) { - if (liveStackFrameClass.isInstance(f)) + if (liveStackFrameClass.isInstance(f)) { throw new RuntimeException("should not be LiveStackFrame"); + } } } + // Use local variables so they stay alive + System.out.println("Stayin' alive: "+x+" "+c+" "+hi+" "+l+" "+d); } String type(Object o) throws Exception { - if (primitiveValueClass.isInstance(o)) { + if (o == null) { + return "null"; + } else if (primitiveValueClass.isInstance(o)) { char c = (char)primitiveType.invoke(o); return String.valueOf(c); } else { diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/lang/invoke/8076596/Test8076596.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8076596/Test8076596.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8076596 + * @run main/othervm/policy=Test8076596.security.policy/secure=Test8076596 -ea -esa Test8076596 + */ + +import java.security.AccessController; +import java.security.PrivilegedAction; + +public class Test8076596 extends SecurityManager { + public Test8076596() { + // 1. Using lambda + AccessController.doPrivileged((PrivilegedAction) () -> null); + // 2. Using inner class + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + return null; + } + }); + } + + public static void main(String[] args) { + // empty + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/lang/invoke/8076596/Test8076596.security.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8076596/Test8076596.security.policy Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,8 @@ +/* + * Security policy used by the Test8076596. + * Must allow file reads so that jtreg itself can run. + */ + +grant { + permission java.io.FilePermission "*", "read"; +}; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/lang/invoke/8147078/Test8147078.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/invoke/8147078/Test8147078.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8147078 + * @run testng/othervm -ea -esa Test8147078 + */ + +import org.testng.annotations.Test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; + +import static java.lang.invoke.MethodType.methodType; + +import static org.testng.AssertJUnit.*; + +public class Test8147078 { + + static int target(int x) { + throw new RuntimeException("ieps"); + } + + static int handler(String s, int x) { + return 4*x; + } + + static final MethodHandle MH_target; + static final MethodHandle MH_handler; + static final MethodHandle MH_catchException; + + static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + static { + try { + Class C = Test8147078.class; + MH_target = LOOKUP.findStatic(C, "target", methodType(int.class, int.class)); + MH_handler = LOOKUP.findStatic(C, "handler", methodType(int.class, String.class, int.class)); + MH_catchException = LOOKUP.findStatic(MethodHandles.class, "catchException", + methodType(MethodHandle.class, MethodHandle.class, Class.class, MethodHandle.class)); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + + @Test + public void testNoExceptionType() { + boolean caught = false; + try { + MethodHandle eek = (MethodHandle) MH_catchException.invoke(MH_target, String.class, MH_handler); + } catch (ClassCastException cce) { + assertEquals("java.lang.String", cce.getMessage()); + caught = true; + } catch (Throwable t) { + fail("unexpected exception caught: " + t); + } + assertTrue(caught); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/lang/invoke/FindClassSecurityManager.java --- a/jdk/test/java/lang/invoke/FindClassSecurityManager.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/lang/invoke/FindClassSecurityManager.java Wed Jul 05 21:13:10 2017 +0200 @@ -24,6 +24,7 @@ */ /* @test + * @bug 8139885 * @run main/othervm/policy=findclass.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.FindClassSecurityManager */ diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/lang/invoke/T8139885.java --- a/jdk/test/java/lang/invoke/T8139885.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/lang/invoke/T8139885.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ */ /* @test + * @bug 8139885 + * @bug 8143798 * @run testng/othervm -ea -esa test.java.lang.invoke.T8139885 */ diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/lang/ref/CleanerTest.java --- a/jdk/test/java/lang/ref/CleanerTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/lang/ref/CleanerTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,9 +34,10 @@ import java.util.function.Consumer; import java.util.function.Supplier; -import jdk.internal.misc.CleanerImpl.PhantomCleanable; -import jdk.internal.misc.CleanerImpl.WeakCleanable; -import jdk.internal.misc.CleanerImpl.SoftCleanable; +import jdk.internal.ref.PhantomCleanable; +import jdk.internal.ref.WeakCleanable; +import jdk.internal.ref.SoftCleanable; +import jdk.internal.ref.CleanerFactory; import sun.hotspot.WhiteBox; @@ -48,17 +49,17 @@ * @test * @library /lib/testlibrary /test/lib * @build sun.hotspot.WhiteBox - * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.misc java.base/jdk.internal.ref * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run testng/othervm * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * -verbose:gc -Xmx4m CleanerTest + * -verbose:gc CleanerTest */ @Test public class CleanerTest { // A common CleaningService used by the test for notifications - static final Cleaner COMMON = Cleaner.create(); + static final Cleaner COMMON = CleanerFactory.cleaner(); // Access to WhiteBox utilities static final WhiteBox whitebox = WhiteBox.getWhiteBox(); @@ -702,4 +703,17 @@ cleaner = null; } + /** + * Test the Cleaner from the CleanerFactory. + */ + @Test + void testCleanerFactory() { + Cleaner cleaner = CleanerFactory.cleaner(); + + Object obj = new Object(); + CleanableCase s = setupPhantom(cleaner, obj); + obj = null; + Assert.assertTrue(checkCleaned(s.getSemaphore()), + "Object cleaning should have occurred using CleanerFactor.cleaner()"); + } } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java --- a/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,11 @@ } catch (Exception ex) { throw new RuntimeException("Setting DatagramSocketImplFactory failed!"); } - new QuoteServerThread().start(); + + QuoteServerThread server = new QuoteServerThread(); + int port = server.getPort(); + System.out.println("Server port is " + port); + server.start(); // get a datagram socket DatagramSocket socket = new DatagramSocket(); @@ -49,7 +53,7 @@ // send request byte[] buf = new byte[256]; InetAddress address = InetAddress.getLocalHost(); - DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4445); + DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port); socket.send(packet); // get response @@ -67,6 +71,7 @@ class QuoteServerThread extends Thread { protected DatagramSocket socket = null; + private final int port; public QuoteServerThread() throws IOException { this("QuoteServerThread"); @@ -74,7 +79,11 @@ public QuoteServerThread(String name) throws IOException { super(name); - socket = new DatagramSocket(4445); + socket = new DatagramSocket(0); + port = socket.getLocalPort(); + } + public int getPort(){ + return port; } public void run() { @@ -101,3 +110,4 @@ socket.close(); } } + diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.net.ExtendedSocketOptions; + +import java.io.IOException; +import java.net.*; + +/* + * @test + * @bug 8143554 + * @run main UnsupportedOptionsTest + * @summary Test checks that UnsupportedOperationException for unsupported + * SOCKET_OPTIONS is thrown by both getOption() and setOption() methods. + */ +public class UnsupportedOptionsTest { + + private static final SocketOption[] SOCKET_OPTIONS = { + StandardSocketOptions.IP_MULTICAST_IF, + StandardSocketOptions.IP_MULTICAST_LOOP, + StandardSocketOptions.IP_MULTICAST_TTL, + StandardSocketOptions.IP_TOS, + StandardSocketOptions.SO_BROADCAST, + StandardSocketOptions.SO_KEEPALIVE, + StandardSocketOptions.SO_LINGER, + StandardSocketOptions.SO_RCVBUF, + StandardSocketOptions.SO_REUSEADDR, + StandardSocketOptions.SO_SNDBUF, + StandardSocketOptions.TCP_NODELAY, + ExtendedSocketOptions.SO_FLOW_SLA + }; + + public static void main(String[] args) throws IOException { + Socket s = new Socket(); + ServerSocket ss = new ServerSocket(); + DatagramSocket ds = new DatagramSocket(); + MulticastSocket ms = new MulticastSocket(); + + for (SocketOption option : SOCKET_OPTIONS) { + if (!s.supportedOptions().contains(option)) { + testUnsupportedSocketOption(s, option); + } + + if (!ss.supportedOptions().contains(option)) { + testUnsupportedSocketOption(ss, option); + } + + if (!ms.supportedOptions().contains(option)) { + testUnsupportedSocketOption(ms, option); + } + + if (!ds.supportedOptions().contains(option)) { + testUnsupportedSocketOption(ds, option); + } + } + } + + /* + * Check that UnsupportedOperationException for unsupported option is + * thrown from both getOption() and setOption() methods. + */ + private static void testUnsupportedSocketOption(Object socket, + SocketOption option) { + testSet(socket, option); + testGet(socket, option); + } + + private static void testSet(Object socket, SocketOption option) { + try { + setOption(socket, option); + } catch (UnsupportedOperationException e) { + System.out.println("UnsupportedOperationException was throw " + + "as expected. Socket: " + socket + " Option: " + option); + return; + } catch (Exception e) { + throw new RuntimeException("FAIL. Unexpected exception.", e); + } + throw new RuntimeException("FAIL. UnsupportedOperationException " + + "hasn't been thrown. Socket: " + socket + " Option: " + option); + } + + private static void testGet(Object socket, SocketOption option) { + try { + getOption(socket, option); + } catch (UnsupportedOperationException e) { + System.out.println("UnsupportedOperationException was throw " + + "as expected. Socket: " + socket + " Option: " + option); + return; + } catch (Exception e) { + throw new RuntimeException("FAIL. Unexpected exception.", e); + } + throw new RuntimeException("FAIL. UnsupportedOperationException " + + "hasn't been thrown. Socket: " + socket + " Option: " + option); + } + + private static void getOption(Object socket, + SocketOption option) throws IOException { + if (socket instanceof Socket) { + ((Socket) socket).getOption(option); + } else if (socket instanceof ServerSocket) { + ((ServerSocket) socket).getOption(option); + } else if (socket instanceof DatagramSocket) { + ((DatagramSocket) socket).getOption(option); + } else { + throw new RuntimeException("Unsupported socket type"); + } + } + + private static void setOption(Object socket, + SocketOption option) throws IOException { + if (socket instanceof Socket) { + ((Socket) socket).setOption(option, null); + } else if (socket instanceof ServerSocket) { + ((ServerSocket) socket).setOption(option, null); + } else if (socket instanceof DatagramSocket) { + ((DatagramSocket) socket).setOption(option, null); + } else { + throw new RuntimeException("Unsupported socket type"); + } + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/nio/channels/ServerSocketChannel/Basic.java --- a/jdk/test/java/nio/channels/ServerSocketChannel/Basic.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/nio/channels/ServerSocketChannel/Basic.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ /* @test + * @bug 4286936 8143100 * @summary Unit test for server-socket channels * @library .. */ @@ -130,7 +131,7 @@ Client client = new Client(port, block); server.start(); client.start(); - if ((server.finish(2000) & client.finish(100)) == 0) + if ((server.finish(0) & client.finish(0)) == 0) throw new Exception("Failure"); log.println(); } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/nio/channels/ServerSocketChannel/NonBlockingAccept.java --- a/jdk/test/java/nio/channels/ServerSocketChannel/NonBlockingAccept.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/nio/channels/ServerSocketChannel/NonBlockingAccept.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ */ /* @test - * @bug 4801882 5046333 + * @bug 4801882 5046333 8141595 * @summary test ServerSocketAdaptor.accept on nonblocking channel * @library .. * @build TestUtil @@ -57,8 +57,17 @@ SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); sc.connect(isa); - Thread.sleep(100); - ss.accept(); + + // loop until accepted + while (true) { + try { + ss.accept(); + break; + } catch (IllegalBlockingModeException ex) { + System.out.println(ex + ", sleeping ..."); + Thread.sleep(100); + } + } } diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/time/tck/java/time/TCKLocalDate.java --- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1285,12 +1285,36 @@ public void test_plusWeeks_invalidMaxMinusMin() { LocalDate.of(Year.MAX_VALUE, 12, 25).plusWeeks(Long.MIN_VALUE); } + //----------------------------------------------------------------------- + @DataProvider(name="PlusDays") + Object[][] provider_plusDays() { + return new Object[][] { + {LocalDate.of(2007, 7, 15), 1, LocalDate.of(2007, 7, 16)}, + {LocalDate.of(2007, 7, 15), 17, LocalDate.of(2007, 8, 1)}, + {LocalDate.of(2007, 12, 31), 1, LocalDate.of(2008, 1, 1)}, + {LocalDate.of(2007, 1, 1), 58, LocalDate.of(2007, 2, 28)}, + {LocalDate.of(2007, 1, 1), 59, LocalDate.of(2007, 3, 1)}, + {LocalDate.of(2008, 1, 1), 60, LocalDate.of(2008, 3, 1)}, + {LocalDate.of(2007, 2, 1), 27, LocalDate.of(2007, 2, 28)}, + {LocalDate.of(2007, 2, 1), 28, LocalDate.of(2007, 3, 1)}, + {LocalDate.of(2007, 1, 1), 29, LocalDate.of(2007, 1, 30)}, + {LocalDate.of(2007, 1, 1), 30, LocalDate.of(2007, 1, 31)}, + {LocalDate.of(2007, 1, 15), 13, LocalDate.of(2007, 1, 28)}, + {LocalDate.of(2007, 1, 15), 14, LocalDate.of(2007, 1, 29)}, + {LocalDate.of(2007, 1, 15), 15, LocalDate.of(2007, 1, 30)}, + {LocalDate.of(2007, 1, 15), 16, LocalDate.of(2007, 1, 31)}, + {LocalDate.of(2007, 2, 15), 13, LocalDate.of(2007, 2, 28)}, + {LocalDate.of(2007, 2, 15), 14, LocalDate.of(2007, 3, 1)}, + {LocalDate.of(2007, 2, 15), 15, LocalDate.of(2007, 3, 2)}, + {LocalDate.of(2007, 2, 15), 16, LocalDate.of(2007, 3, 3)}, + }; + } - @Test - public void test_plusDays_normal() { - LocalDate t = TEST_2007_07_15.plusDays(1); - assertEquals(t, LocalDate.of(2007, 7, 16)); - } + @Test(dataProvider="PlusDays") + public void test_plusDays_normal(LocalDate input, int amountsToAdd, LocalDate expected) { + LocalDate actual = input.plusDays(amountsToAdd); + assertEquals(actual, expected); + } @Test public void test_plusDays_overMonths() { diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/util/Locale/Bug8026766.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/util/Locale/Bug8026766.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8026766 + * @summary Confirm that LanguageRange.toString() returns an expected result. + * @run main Bug8026766 + */ + +import java.util.Locale.LanguageRange; + +public class Bug8026766 { + + public static void main(String[] args) { + LanguageRange lr1 = new LanguageRange("ja", 1.0); + LanguageRange lr2 = new LanguageRange("fr", 0.0); + + if (!lr1.toString().equals("ja") || + !lr2.toString().equals("fr;q=0.0")) { + throw new RuntimeException("LanguageRange.toString() returned an unexpected result."); + } + } + +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java --- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java Wed Jul 05 21:13:10 2017 +0200 @@ -37,6 +37,7 @@ * @bug 8004138 * @summary Check if ForkJoinPool table leaks thrown exceptions. * @run main/othervm -Xmx2200k FJExceptionTableLeak + * @key intermittent */ import java.util.concurrent.ForkJoinPool; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java --- a/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/java/util/logging/LogManager/Configuration/updateConfiguration/UpdateConfigurationTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -209,8 +209,9 @@ + barChild.getParent() +"\n\texpected: " + barRef.get()); } Reference ref2; - int max = 3; + int max = 10; barChild = null; + System.gc(); while ((ref2 = queue.poll()) == null) { System.gc(); Thread.sleep(100); @@ -276,24 +277,27 @@ } }); - // Now we need to forget the child, so that loggers are released, - // and so that we can run the test with the next configuration... - - fooChild = null; - System.out.println("Setting fooChild to: " + fooChild); - while ((ref2 = queue.poll()) == null) { - System.gc(); - Thread.sleep(1000); + if (suppressed == null) { + // Now we need to forget the child, so that loggers are released, + // and so that we can run the test with the next configuration... + // No need to do that if failed!=null however, as the first + // ref might not have been cleared yet and failing here would + // hide the original failure. + fooChild = null; + System.out.println("Setting fooChild to: " + fooChild); + while ((ref2 = queue.poll()) == null) { + System.gc(); + Thread.sleep(1000); + } + if (ref2 != fooRef) { + throw new RuntimeException("Unexpected reference: " + + ref2 +"\n\texpected: " + fooRef); + } + if (ref2.get() != null) { + throw new RuntimeException("Referent not cleared: " + ref2.get()); + } + System.out.println("Got fooRef after reset(), fooChild is " + fooChild); } - if (ref2 != fooRef) { - throw new RuntimeException("Unexpected reference: " - + ref2 +"\n\texpected: " + fooRef); - } - if (ref2.get() != null) { - throw new RuntimeException("Referent not cleared: " + ref2.get()); - } - System.out.println("Got fooRef after reset(), fooChild is " + fooChild); - } } if (failed != null) { diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/net/ssl/ALPN/MyX509ExtendedKeyManager.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.net.Socket; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.X509ExtendedKeyManager; + +public class MyX509ExtendedKeyManager extends X509ExtendedKeyManager { + + static final String ERROR = "ERROR"; + X509ExtendedKeyManager akm; + String expectedAP; + + MyX509ExtendedKeyManager(X509ExtendedKeyManager akm) { + this.akm = akm; + } + + public MyX509ExtendedKeyManager( + X509ExtendedKeyManager akm, String expectedAP) { + this.akm = akm; + this.expectedAP = expectedAP; + + } + + @Override + public String[] getClientAliases(String keyType, Principal[] issuers) { + return akm.getClientAliases(keyType, issuers); + } + + @Override + public String chooseClientAlias(String[] keyType, Principal[] issuers, + Socket socket) { + String nap = ((SSLSocket) socket).getHandshakeApplicationProtocol(); + checkALPN(nap); + + return akm.chooseClientAlias(keyType, issuers, socket); + } + + @Override + public String[] getServerAliases(String keyType, Principal[] issuers) { + return akm.getServerAliases(keyType, issuers); + } + + @Override + public String chooseServerAlias(String keyType, Principal[] issuers, + Socket socket) { + String nap = ((SSLSocket) socket).getHandshakeApplicationProtocol(); + checkALPN(nap); + + return akm.chooseServerAlias(keyType, issuers, socket); + } + + @Override + public X509Certificate[] getCertificateChain(String alias) { + return akm.getCertificateChain(alias); + } + + @Override + public PrivateKey getPrivateKey(String alias) { + return akm.getPrivateKey(alias); + } + + @Override + public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, + SSLEngine engine) { + String nap = engine.getHandshakeApplicationProtocol(); + checkALPN(nap); + + return akm.chooseEngineClientAlias(keyType, issuers, engine); + } + + @Override + public String chooseEngineServerAlias(String keyType, Principal[] issuers, + SSLEngine engine) { + String nap = engine.getHandshakeApplicationProtocol(); + checkALPN(nap); + + return akm.chooseEngineServerAlias(keyType, issuers, engine); + } + + private void checkALPN(String ap) { + + if (ERROR.equals(expectedAP)) { + throw new RuntimeException("Should not reach here"); + } + + System.out.println("Expected ALPN value: " + expectedAP + + " Got: " + ap); + + if (ap == null) { + throw new RuntimeException( + "ALPN should be negotiated, but null was received"); + } + if (expectedAP.equals("NONE")) { + if (!ap.isEmpty()) { + throw new RuntimeException("Expected no ALPN value"); + } else { + System.out.println("No ALPN value negotiated, as expected"); + } + } else if (!expectedAP.equals(ap)) { + throw new RuntimeException(expectedAP + + " ALPN value not available on negotiated connection"); + } + + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java --- a/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,9 @@ /* * @test - * @bug 8051498 + * @bug 8051498 8145849 * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension + * @compile MyX509ExtendedKeyManager.java * @run main/othervm SSLEngineAlpnTest h2 h2 h2 * @run main/othervm SSLEngineAlpnTest h2 h2,http/1.1 h2 * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2,http/1.1 h2 @@ -162,7 +163,7 @@ throw new Exception("Invalid number of test parameters"); } - SSLEngineAlpnTest test = new SSLEngineAlpnTest(); + SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[2]); try { test.runTest(convert(args[0]), convert(args[1]), args[2]); } catch (SSLHandshakeException she) { @@ -179,7 +180,7 @@ /* * Create an initialized SSLContext to use for these tests. */ - public SSLEngineAlpnTest() throws Exception { + public SSLEngineAlpnTest(String expectedAP) throws Exception { KeyStore ks = KeyStore.getInstance("JKS"); KeyStore ts = KeyStore.getInstance("JKS"); @@ -192,12 +193,20 @@ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, passphrase); + KeyManager [] kms = kmf.getKeyManagers(); + if (!(kms[0] instanceof X509ExtendedKeyManager)) { + throw new Exception("kms[0] not X509ExtendedKeyManager"); + } + + kms = new KeyManager[] { new MyX509ExtendedKeyManager( + (X509ExtendedKeyManager) kms[0], expectedAP) }; + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ts); SSLContext sslCtx = SSLContext.getInstance("TLS"); - sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + sslCtx.init(kms, tmf.getTrustManagers(), null); sslc = sslCtx; } @@ -327,6 +336,11 @@ return; } + if (engine.getHandshakeApplicationProtocol() != null) { + throw new Exception ("getHandshakeApplicationProtocol() should " + + "return null after the handshake is completed"); + } + String ap = engine.getApplicationProtocol(); System.out.println("Application Protocol: \"" + ap + "\""); @@ -384,6 +398,12 @@ sslp = clientEngine.getSSLParameters(); sslp.setApplicationProtocols(clientAPs); clientEngine.setSSLParameters(sslp); + + if ((clientEngine.getHandshakeApplicationProtocol() != null) || + (serverEngine.getHandshakeApplicationProtocol() != null)) { + throw new Exception ("getHandshakeApplicationProtocol() should " + + "return null before the handshake starts"); + } } /* diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java --- a/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/javax/net/ssl/ALPN/SSLSocketAlpnTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,9 @@ /* * @test - * @bug 8051498 + * @bug 8051498 8145849 * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension + * @compile MyX509ExtendedKeyManager.java * @run main/othervm SSLSocketAlpnTest h2 h2 h2 * @run main/othervm SSLSocketAlpnTest h2 h2,http/1.1 h2 * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2,http/1.1 h2 @@ -40,6 +41,8 @@ * @author Brad Wetmore */ import java.io.*; +import java.security.KeyStore; + import javax.net.ssl.*; public class SSLSocketAlpnTest { @@ -65,6 +68,16 @@ static String trustStoreFile = "truststore"; static String passwd = "passphrase"; + static String keyFilename = System.getProperty("test.src", ".") + "/" + + pathToStores + "/" + keyStoreFile; + static String trustFilename = System.getProperty("test.src", ".") + "/" + + pathToStores + "/" + trustStoreFile; + + /* + * SSLContext + */ + SSLContext mySSLContext = null; + /* * Is the server ready to serve? */ @@ -82,7 +95,7 @@ /* * If the client or server is doing some kind of object creation * that the other side depends on, and that thread prematurely - * exits, you may experience a hang. The test harness will + * exits, you may experience a hang. The test harness will * terminate all hung threads after its timeout has expired, * currently 3 minutes by default, but you might try to be * smart about it.... @@ -95,10 +108,11 @@ * to avoid infinite hangs. */ void doServerSide() throws Exception { - SSLServerSocketFactory sslssf - = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory(); SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); + // for both client/server to call into X509KM + sslServerSocket.setNeedClientAuth(true); serverPort = sslServerSocket.getLocalPort(); @@ -119,20 +133,30 @@ */ String[] suites = sslp.getCipherSuites(); sslp.setCipherSuites(suites); - sslp.setUseCipherSuitesOrder(true); // Set server side order + sslp.setUseCipherSuitesOrder(true); // Set server side order // Set the ALPN selection. sslp.setApplicationProtocols(serverAPs); sslSocket.setSSLParameters(sslp); + if (sslSocket.getHandshakeApplicationProtocol() != null) { + throw new Exception ("getHandshakeApplicationProtocol() should " + + "return null before the handshake starts"); + } + sslSocket.startHandshake(); + if (sslSocket.getHandshakeApplicationProtocol() != null) { + throw new Exception ("getHandshakeApplicationProtocol() should " + + "return null after the handshake is completed"); + } + String ap = sslSocket.getApplicationProtocol(); System.out.println("Application Protocol: \"" + ap + "\""); if (ap == null) { throw new Exception( - "Handshake was completed but null was received"); + "Handshake was completed but null was received"); } if (expectedAP.equals("NONE")) { if (!ap.isEmpty()) { @@ -141,8 +165,8 @@ System.out.println("No ALPN value negotiated, as expected"); } } else if (!expectedAP.equals(ap)) { - throw new Exception(expectedAP + - " ALPN value not available on negotiated connection"); + throw new Exception(expectedAP + + " ALPN value not available on negotiated connection"); } InputStream sslIS = sslSocket.getInputStream(); @@ -170,8 +194,7 @@ Thread.sleep(50); } - SSLSocketFactory sslsf - = (SSLSocketFactory) SSLSocketFactory.getDefault(); + SSLSocketFactory sslsf = mySSLContext.getSocketFactory(); SSLSocket sslSocket = (SSLSocket) sslsf.createSocket("localhost", serverPort); @@ -185,28 +208,35 @@ */ String[] suites = sslp.getCipherSuites(); sslp.setCipherSuites(suites); - sslp.setUseCipherSuitesOrder(true); // Set server side order + sslp.setUseCipherSuitesOrder(true); // Set server side order // Set the ALPN selection. sslp.setApplicationProtocols(clientAPs); sslSocket.setSSLParameters(sslp); + if (sslSocket.getHandshakeApplicationProtocol() != null) { + throw new Exception ("getHandshakeApplicationProtocol() should " + + "return null before the handshake starts"); + } + sslSocket.startHandshake(); + if (sslSocket.getHandshakeApplicationProtocol() != null) { + throw new Exception ("getHandshakeApplicationProtocol() should " + + "return null after the handshake is completed"); + } + /* * Check that the resulting connection meets our defined ALPN * criteria. If we were connecting to a non-JSSE implementation, * the server might have negotiated something we shouldn't accept. - * - * We were expecting H2 from server, let's make sure the - * conditions match. */ String ap = sslSocket.getApplicationProtocol(); System.out.println("Application Protocol: \"" + ap + "\""); if (ap == null) { throw new Exception( - "Handshake was completed but null was received"); + "Handshake was completed but null was received"); } if (expectedAP.equals("NONE")) { if (!ap.isEmpty()) { @@ -215,8 +245,8 @@ System.out.println("No ALPN value negotiated, as expected"); } } else if (!expectedAP.equals(ap)) { - throw new Exception(expectedAP + - " ALPN value not available on negotiated connection"); + throw new Exception(expectedAP + + " ALPN value not available on negotiated connection"); } InputStream sslIS = sslSocket.getInputStream(); @@ -240,17 +270,6 @@ volatile Exception clientException = null; public static void main(String[] args) throws Exception { - String keyFilename - = System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + keyStoreFile; - String trustFilename - = System.getProperty("test.src", ".") + "/" + pathToStores - + "/" + trustStoreFile; - - System.setProperty("javax.net.ssl.keyStore", keyFilename); - System.setProperty("javax.net.ssl.keyStorePassword", passwd); - System.setProperty("javax.net.ssl.trustStore", trustFilename); - System.setProperty("javax.net.ssl.trustStorePassword", passwd); if (debug) { System.setProperty("javax.net.debug", "all"); @@ -280,6 +299,39 @@ System.out.println("Test Passed."); } + SSLContext getSSLContext(String keyFilename, String trustFilename) + throws Exception { + SSLContext ctx = SSLContext.getInstance("TLS"); + + // Keystores + KeyStore keyKS = KeyStore.getInstance("JKS"); + keyKS.load(new FileInputStream(keyFilename), passwd.toCharArray()); + + KeyStore trustKS = KeyStore.getInstance("JKS"); + trustKS.load(new FileInputStream(trustFilename), passwd.toCharArray()); + + // Generate KeyManager and TrustManager + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(keyKS, passwd.toCharArray()); + + KeyManager[] kms = kmf.getKeyManagers(); + if (!(kms[0] instanceof X509ExtendedKeyManager)) { + throw new Exception("kms[0] not X509ExtendedKeyManager"); + } + + kms = new KeyManager[] { new MyX509ExtendedKeyManager( + (X509ExtendedKeyManager) kms[0], expectedAP) }; + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(trustKS); + TrustManager[] tms = tmf.getTrustManagers(); + + // initial SSLContext + ctx.init(kms, tms, null); + + return ctx; + } + /* * Convert a comma-separated list into an array of strings. */ @@ -309,6 +361,7 @@ */ SSLSocketAlpnTest() throws Exception { Exception startException = null; + mySSLContext = getSSLContext(keyFilename, trustFilename); try { if (separateServerThread) { startServer(true); diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java --- a/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ * @bug 4366807 * @summary Need new APIs to get/set session timeout and session cache size. * @run main/othervm SessionCacheSizeTests + * @key intermittent */ import java.io.*; @@ -108,28 +109,34 @@ void doServerSide(int serverPort, int serverConns) throws Exception { - SSLServerSocket sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(serverPort); - sslServerSocket.setSoTimeout(45000); // timeout to accept a connection - serverPorts[createdPorts++] = sslServerSocket.getLocalPort(); + try (SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket(serverPort)) { + + // timeout to accept a connection + sslServerSocket.setSoTimeout(45000); + + // make sure createdPorts++ is atomic + synchronized(serverPorts) { + serverPorts[createdPorts++] = sslServerSocket.getLocalPort(); - /* - * Signal Client, we're ready for his connect. - */ - if (createdPorts == serverPorts.length) { - serverReady = true; - } - int read = 0; - int nConnections = 0; - /* - * Divide the max connections among the available server ports. - * The use of more than one server port ensures creation of more - * than one session. - */ - SSLSession sessions [] = new SSLSession [serverConns]; - SSLSessionContext sessCtx = sslctx.getServerSessionContext(); + /* + * Signal Client, we're ready for his connect. + */ + if (createdPorts == serverPorts.length) { + serverReady = true; + } + } + int read = 0; + int nConnections = 0; - try { + /* + * Divide the max connections among the available server ports. + * The use of more than one server port ensures creation of more + * than one session. + */ + SSLSession sessions [] = new SSLSession [serverConns]; + SSLSessionContext sessCtx = sslctx.getServerSessionContext(); + while (nConnections < serverConns) { try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) { @@ -143,8 +150,6 @@ nConnections++; } } - } finally { - sslServerSocket.close(); } } @@ -270,8 +275,8 @@ * Using four ports (one per each connection), we are able to create * alteast four sessions. */ - volatile int serverPorts[] = new int[]{0, 0, 0, 0}; - volatile int createdPorts = 0; + int serverPorts[] = new int[]{0, 0, 0, 0}; // MAX_ACTIVE_CONNECTIONS: 4 + int createdPorts = 0; static SSLServerSocketFactory sslssf; static SSLSocketFactory sslsf; static SSLContext sslctx; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/javax/security/auth/SubjectDomainCombiner/Optimize.java --- a/jdk/test/javax/security/auth/SubjectDomainCombiner/Optimize.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/javax/security/auth/SubjectDomainCombiner/Optimize.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,13 +37,16 @@ ProtectionDomain pd1 = new ProtectionDomain( new CodeSource(null, (java.security.cert.Certificate[]) null), - new Permissions()); + new Permissions(), + null, null); ProtectionDomain pd2 = new ProtectionDomain( new CodeSource(null, (java.security.cert.Certificate[]) null), - new Permissions()); + new Permissions(), + null, null); ProtectionDomain pd3 = new ProtectionDomain( new CodeSource(null, (java.security.cert.Certificate[]) null), - new Permissions()); + new Permissions(), + null, null); ProtectionDomain[] current = new ProtectionDomain[] {pd1, pd2}; ProtectionDomain[] assigned = new ProtectionDomain[] {pd3, pd2}; diff -r 3c05feabae49 -r 2dc4c11fe488 jdk/test/jdk/internal/jimage/JImageReadTest.java --- a/jdk/test/jdk/internal/jimage/JImageReadTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/jdk/test/jdk/internal/jimage/JImageReadTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -313,7 +313,7 @@ static boolean isMetaName(String name) { return name.startsWith("/modules") || name.startsWith("/packages") - || name.startsWith("META-INF/services") + || name.startsWith("META-INF") || name.equals("bootmodules.jdata"); } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/.hgtags --- a/langtools/.hgtags Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/.hgtags Wed Jul 05 21:13:10 2017 +0200 @@ -343,3 +343,4 @@ 345520da2ec17100cb512a53d541a307a195305e jdk-9+98 cb73b474703e2de266542b505cffd658bcc052da jdk-9+99 51136404ee5e6cd5868b60d66ebd55a02170b508 jdk-9+100 +3b3bea483542bc08278af529fb25f2e5930da945 jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java Wed Jul 05 21:13:10 2017 +0200 @@ -1146,14 +1146,21 @@ if (!visit(supertype(t), supertype(s))) return false; - HashSet set = new HashSet<>(); - for (Type x : interfaces(t)) - set.add(new UniqueType(x, Types.this)); - for (Type x : interfaces(s)) { - if (!set.remove(new UniqueType(x, Types.this))) + Map tMap = new HashMap<>(); + for (Type ti : interfaces(t)) { + if (tMap.containsKey(ti)) { + throw new AssertionError("Malformed intersection"); + } + tMap.put(ti.tsym, ti); + } + for (Type si : interfaces(s)) { + if (!tMap.containsKey(si.tsym)) + return false; + Type ti = tMap.remove(si.tsym); + if (!visit(ti, si)) return false; } - return (set.isEmpty()); + return tMap.isEmpty(); } return t.tsym == s.tsym && visit(t.getEnclosingType(), s.getEnclosingType()) diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java Wed Jul 05 21:13:10 2017 +0200 @@ -1137,7 +1137,56 @@ /** Parameters {@code t} and {@code s} are unrelated functional interface types. */ private boolean functionalInterfaceMostSpecific(Type t, Type s, JCTree tree) { - FunctionalInterfaceMostSpecificChecker msc = new FunctionalInterfaceMostSpecificChecker(t, s); + Type tDesc = types.findDescriptorType(t); + Type sDesc = types.findDescriptorType(s); + + // compare type parameters -- can't use Types.hasSameBounds because bounds may have ivars + final List tTypeParams = tDesc.getTypeArguments(); + final List sTypeParams = sDesc.getTypeArguments(); + List tIter = tTypeParams; + List sIter = sTypeParams; + while (tIter.nonEmpty() && sIter.nonEmpty()) { + Type tBound = tIter.head.getUpperBound(); + Type sBound = types.subst(sIter.head.getUpperBound(), sTypeParams, tTypeParams); + if (tBound.containsAny(tTypeParams) && inferenceContext().free(sBound)) { + return false; + } + if (!types.isSameType(tBound, inferenceContext().asUndetVar(sBound))) { + return false; + } + tIter = tIter.tail; + sIter = sIter.tail; + } + if (!tIter.isEmpty() || !sIter.isEmpty()) { + return false; + } + + // compare parameters + List tParams = tDesc.getParameterTypes(); + List sParams = sDesc.getParameterTypes(); + while (tParams.nonEmpty() && sParams.nonEmpty()) { + Type tParam = tParams.head; + Type sParam = types.subst(sParams.head, sTypeParams, tTypeParams); + if (tParam.containsAny(tTypeParams) && inferenceContext().free(sParam)) { + return false; + } + if (!types.isSameType(tParam, inferenceContext().asUndetVar(sParam))) { + return false; + } + tParams = tParams.tail; + sParams = sParams.tail; + } + if (!tParams.isEmpty() || !sParams.isEmpty()) { + return false; + } + + // compare returns + Type tRet = tDesc.getReturnType(); + Type sRet = types.subst(sDesc.getReturnType(), sTypeParams, tTypeParams); + if (tRet.containsAny(tTypeParams) && inferenceContext().free(sRet)) { + return false; + } + MostSpecificFunctionReturnChecker msc = new MostSpecificFunctionReturnChecker(tRet, sRet); msc.scan(tree); return msc.result; } @@ -1146,16 +1195,16 @@ * Tests whether one functional interface type can be considered more specific * than another unrelated functional interface type for the scanned expression. */ - class FunctionalInterfaceMostSpecificChecker extends DeferredAttr.PolyScanner { - - final Type t; - final Type s; + class MostSpecificFunctionReturnChecker extends DeferredAttr.PolyScanner { + + final Type tRet; + final Type sRet; boolean result; /** Parameters {@code t} and {@code s} are unrelated functional interface types. */ - FunctionalInterfaceMostSpecificChecker(Type t, Type s) { - this.t = t; - this.s = s; + MostSpecificFunctionReturnChecker(Type tRet, Type sRet) { + this.tRet = tRet; + this.sRet = sRet; result = true; } @@ -1172,29 +1221,18 @@ @Override public void visitReference(JCMemberReference tree) { - Type desc_t = types.findDescriptorType(t); - Type desc_s = types.findDescriptorType(s); - // use inference variables here for more-specific inference (18.5.4) - if (!types.isSameTypes(desc_t.getParameterTypes(), - inferenceContext().asUndetVars(desc_s.getParameterTypes()))) { + if (sRet.hasTag(VOID)) { + result &= true; + } else if (tRet.hasTag(VOID)) { result &= false; + } else if (tRet.isPrimitive() != sRet.isPrimitive()) { + boolean retValIsPrimitive = + tree.refPolyKind == PolyKind.STANDALONE && + tree.sym.type.getReturnType().isPrimitive(); + result &= (retValIsPrimitive == tRet.isPrimitive()) && + (retValIsPrimitive != sRet.isPrimitive()); } else { - // compare return types - Type ret_t = desc_t.getReturnType(); - Type ret_s = desc_s.getReturnType(); - if (ret_s.hasTag(VOID)) { - result &= true; - } else if (ret_t.hasTag(VOID)) { - result &= false; - } else if (ret_t.isPrimitive() != ret_s.isPrimitive()) { - boolean retValIsPrimitive = - tree.refPolyKind == PolyKind.STANDALONE && - tree.sym.type.getReturnType().isPrimitive(); - result &= (retValIsPrimitive == ret_t.isPrimitive()) && - (retValIsPrimitive != ret_s.isPrimitive()); - } else { - result &= compatibleBySubtyping(ret_t, ret_s); - } + result &= compatibleBySubtyping(tRet, sRet); } } @@ -1205,32 +1243,24 @@ @Override public void visitLambda(JCLambda tree) { - Type desc_t = types.findDescriptorType(t); - Type desc_s = types.findDescriptorType(s); - // use inference variables here for more-specific inference (18.5.4) - if (!types.isSameTypes(desc_t.getParameterTypes(), - inferenceContext().asUndetVars(desc_s.getParameterTypes()))) { + if (sRet.hasTag(VOID)) { + result &= true; + } else if (tRet.hasTag(VOID)) { result &= false; } else { - // compare return types - Type ret_t = desc_t.getReturnType(); - Type ret_s = desc_s.getReturnType(); - if (ret_s.hasTag(VOID)) { - result &= true; - } else if (ret_t.hasTag(VOID)) { - result &= false; - } else if (unrelatedFunctionalInterfaces(ret_t, ret_s)) { - for (JCExpression expr : lambdaResults(tree)) { - result &= functionalInterfaceMostSpecific(ret_t, ret_s, expr); + List lambdaResults = lambdaResults(tree); + if (!lambdaResults.isEmpty() && unrelatedFunctionalInterfaces(tRet, sRet)) { + for (JCExpression expr : lambdaResults) { + result &= functionalInterfaceMostSpecific(tRet, sRet, expr); } - } else if (ret_t.isPrimitive() != ret_s.isPrimitive()) { - for (JCExpression expr : lambdaResults(tree)) { + } else if (!lambdaResults.isEmpty() && tRet.isPrimitive() != sRet.isPrimitive()) { + for (JCExpression expr : lambdaResults) { boolean retValIsPrimitive = expr.isStandalone() && expr.type.isPrimitive(); - result &= (retValIsPrimitive == ret_t.isPrimitive()) && - (retValIsPrimitive != ret_s.isPrimitive()); + result &= (retValIsPrimitive == tRet.isPrimitive()) && + (retValIsPrimitive != sRet.isPrimitive()); } } else { - result &= compatibleBySubtyping(ret_t, ret_s); + result &= compatibleBySubtyping(tRet, sRet); } } } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -301,15 +301,16 @@ } /** Read a number. - * @param radix The radix of the number; one of 2, j8, 10, 16. + * @param radix The radix of the number; one of 2, 8, 10, 16. */ private void scanNumber(int pos, int radix) { // for octal, allow base-10 digit in case it's a float literal this.radix = radix; int digitRadix = (radix == 8 ? 10 : radix); - boolean seendigit = false; - if (reader.digit(pos, digitRadix) >= 0) { - seendigit = true; + int firstDigit = reader.digit(pos, Math.max(10, digitRadix)); + boolean seendigit = firstDigit >= 0; + boolean seenValidDigit = firstDigit >= 0 && firstDigit < digitRadix; + if (seendigit) { scanDigits(pos, digitRadix); } if (radix == 16 && reader.ch == '.') { @@ -325,6 +326,16 @@ reader.ch == 'd' || reader.ch == 'D')) { scanFractionAndSuffix(pos); } else { + if (!seenValidDigit) { + switch (radix) { + case 2: + lexError(pos, "invalid.binary.number"); + break; + case 16: + lexError(pos, "invalid.hex.number"); + break; + } + } if (reader.ch == 'l' || reader.ch == 'L') { reader.scanChar(); tk = TokenKind.LONGLITERAL; @@ -491,13 +502,7 @@ if (reader.ch == 'x' || reader.ch == 'X') { reader.scanChar(); skipIllegalUnderscores(); - if (reader.ch == '.') { - scanHexFractionAndSuffix(pos, false); - } else if (reader.digit(pos, 16) < 0) { - lexError(pos, "invalid.hex.number"); - } else { - scanNumber(pos, 16); - } + scanNumber(pos, 16); } else if (reader.ch == 'b' || reader.ch == 'B') { if (!allowBinaryLiterals) { lexError(pos, "unsupported.binary.lit", source.name); @@ -505,11 +510,7 @@ } reader.scanChar(); skipIllegalUnderscores(); - if (reader.digit(pos, 2) < 0) { - lexError(pos, "invalid.binary.number"); - } else { - scanNumber(pos, 2); - } + scanNumber(pos, 2); } else { reader.putChar('0'); if (reader.ch == '_') { diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java Wed Jul 05 21:13:10 2017 +0200 @@ -26,11 +26,20 @@ package com.sun.tools.sjavac; import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.Set; import java.util.Collections; import java.util.List; import java.util.ArrayList; import java.util.Map; +import java.util.regex.PatternSyntaxException; /** A Source object maintains information about a source file. * For example which package it belongs to and kind of source it is. @@ -56,8 +65,6 @@ private long lastModified; // The source File. private File file; - // The source root under which file resides. - private File root; // If the source is generated. private boolean isGenerated; // If the source is only linked to, not compiled. @@ -78,7 +85,7 @@ return name.hashCode(); } - public Source(Module m, String n, File f, File r) { + public Source(Module m, String n, File f) { name = n; int dp = n.lastIndexOf("."); if (dp != -1) { @@ -87,7 +94,6 @@ suffix = ""; } file = f; - root = r; lastModified = f.lastModified(); linkedOnly = false; } @@ -102,7 +108,6 @@ suffix = ""; } file = null; - root = null; lastModified = lm; linkedOnly = false; int ls = n.lastIndexOf('/'); @@ -112,7 +117,6 @@ public String suffix() { return suffix; } public Package pkg() { return pkg; } public File file() { return file; } - public File root() { return root; } public long lastModified() { return lastModified; } @@ -183,225 +187,122 @@ */ static public void scanRoot(File root, Set suffixes, - List excludes, List includes, - List excludeFiles, List includeFiles, + List excludes, + List includes, Map foundFiles, Map foundModules, - Module currentModule, + final Module currentModule, boolean permitSourcesWithoutPackage, boolean inGensrc, boolean inLinksrc) - throws ProblemException { + throws IOException, ProblemException { + + if (root == null) + return; + + FileSystem fs = root.toPath().getFileSystem(); + + if (includes.isEmpty()) { + includes = Collections.singletonList("**"); + } + + List includeMatchers = createPathMatchers(fs, includes); + List excludeMatchers = createPathMatchers(fs, excludes); - if (root == null) return; - int root_prefix = root.getPath().length()+1; - // This is the root source directory, it must not contain any Java sources files - // because we do not allow Java source files without a package. - // (Unless of course --permit-sources-without-package has been specified.) - // It might contain other source files however, (for -tr and -copy) these will - // always be included, since no package pattern can match the root directory. - currentModule = addFilesInDir(root, root_prefix, root, suffixes, permitSourcesWithoutPackage, - excludeFiles, includeFiles, - foundFiles, foundModules, currentModule, - inGensrc, inLinksrc); + Files.walkFileTree(root.toPath(), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + + Path relToRoot = root.toPath().relativize(file); - File[] dirfiles = root.listFiles(); - for (File d : dirfiles) { - if (d.isDirectory()) { - // Descend into the directory structure. - scanDirectory(d, root_prefix, root, suffixes, - excludes, includes, excludeFiles, includeFiles, - foundFiles, foundModules, currentModule, inGensrc, inLinksrc); - } - } - } + if (includeMatchers.stream().anyMatch(im -> im.matches(relToRoot)) + && excludeMatchers.stream().noneMatch(em -> em.matches(relToRoot)) + && suffixes.contains(Util.fileSuffix(file))) { + + // TODO: Test this. + Source existing = foundFiles.get(file); + if (existing != null) { + throw new IOException("You have already added the file "+file+" from "+existing.file().getPath()); + } + existing = currentModule.lookupSource(file.toString()); + if (existing != null) { - /** - * Test if a path matches any of the patterns given. - * The pattern foo/bar matches only foo/bar - * The pattern foo/* matches foo/bar and foo/bar/zoo etc - */ - static private boolean hasMatch(String path, List patterns) { - - // Convert Windows '\' to '/' for the sake of comparing with the patterns - path = path.replace(File.separatorChar, '/'); + // Oups, the source is already added, could be ok, could be not, lets check. + if (inLinksrc) { + // So we are collecting sources for linking only. + if (existing.isLinkedOnly()) { + // Ouch, this one is also for linking only. Bad. + throw new IOException("You have already added the link only file " + file + " from " + existing.file().getPath()); + } + // Ok, the existing source is to be compiled. Thus this link only is redundant + // since all compiled are also linked to. Continue to the next source. + // But we need to add the source, so that it will be visible to linking, + // if not the multi core compile will fail because a JavaCompiler cannot + // find the necessary dependencies for its part of the source. + foundFiles.put(file.toString(), existing); + } else { + // We are looking for sources to compile, if we find an existing to be compiled + // source with the same name, it is an internal error, since we must + // find the sources to be compiled before we find the sources to be linked to. + throw new IOException("Internal error: Double add of file " + file + " from " + existing.file().getPath()); + } - for (String p : patterns) { - // Exact match - if (p.equals(path)) - return true; + } else { - // Single dot the end matches this package and all its subpackages. - if (p.endsWith("/*")) { - // Remove the wildcard - String patprefix = p.substring(0,p.length()-2); - // Does the path start with the pattern prefix? - if (path.startsWith(patprefix)) { - // If the path has the same length as the pattern prefix, then it is a match. - // If the path is longer, then make sure that - // the next part of the path starts with a dot (.) to prevent - // wildcard matching in the middle of a package name. - if (path.length()==patprefix.length() || path.charAt(patprefix.length())=='/') { - return true; + ////////////////////////////////////////////////////////////// + // Add source + Source s = new Source(currentModule, file.toString(), file.toFile()); + if (inGensrc) { + s.markAsGenerated(); + } + if (inLinksrc) { + s.markAsLinkedOnly(); + } + String pkg = packageOfJavaFile(root.toPath(), file); + pkg = currentModule.name() + ":" + pkg; + foundFiles.put(file.toString(), s); + currentModule.addSource(pkg, s); + ////////////////////////////////////////////////////////////// } } + + return FileVisitResult.CONTINUE; } - } - return false; - } - - /** - * Matches patterns with the asterisk first. */ - // The pattern foo/bar.java only matches foo/bar.java - // The pattern */bar.java matches foo/bar.java and zoo/bar.java etc - static private boolean hasFileMatch(String path, List patterns) { - // Convert Windows '\' to '/' for the sake of comparing with the patterns - path = path.replace(File.separatorChar, '/'); - - path = Util.normalizeDriveLetter(path); - for (String p : patterns) { - // Exact match - if (p.equals(path)) { - return true; - } - // Single dot the end matches this package and all its subpackages. - if (p.startsWith("*")) { - // Remove the wildcard - String patsuffix = p.substring(1); - // Does the path start with the pattern prefix? - if (path.endsWith(patsuffix)) { - return true; - } - } - } - return false; + }); } - /** - * Add the files in the directory, assuming that the file has not been excluded. - * Returns a fresh Module object, if this was a dir with a module-info.java file. - */ - static private Module addFilesInDir(File dir, int rootPrefix, File root, - Set suffixes, boolean allow_javas, - List excludeFiles, List includeFiles, - Map foundFiles, - Map foundModules, - Module currentModule, - boolean inGensrc, - boolean inLinksrc) - throws ProblemException - { - for (File f : dir.listFiles()) { - - if (!f.isFile()) - continue; - - boolean should_add = - (excludeFiles == null || excludeFiles.isEmpty() || !hasFileMatch(f.getPath(), excludeFiles)) - && (includeFiles == null || includeFiles.isEmpty() || hasFileMatch(f.getPath(), includeFiles)); - - if (!should_add) - continue; - - if (!allow_javas && f.getName().endsWith(".java")) { - throw new ProblemException("No .java files are allowed in the source root "+dir.getPath()+ - ", please remove "+f.getName()); - } - // Extract the file name relative the root. - String fn = f.getPath().substring(rootPrefix); - // Extract the package name. - int sp = fn.lastIndexOf(File.separatorChar); - String pkg = ""; - if (sp != -1) { - pkg = fn.substring(0,sp).replace(File.separatorChar,'.'); - } - // Is this a module-info.java file? - if (fn.endsWith("module-info.java")) { - // Aha! We have recursed into a module! - if (!currentModule.name().equals("")) { - throw new ProblemException("You have an extra module-info.java inside a module! Please remove "+fn); - } - String module_name = fn.substring(0,fn.length()-16); - currentModule = new Module(module_name, f.getPath()); - foundModules.put(module_name, currentModule); - } - // Extract the suffix. - int dp = fn.lastIndexOf("."); - String suffix = ""; - if (dp > 0) { - suffix = fn.substring(dp); - } - // Should the file be added? - if (suffixes.contains(suffix)) { - Source of = foundFiles.get(f.getPath()); - if (of != null) { - throw new ProblemException("You have already added the file "+fn+" from "+of.file().getPath()); - } - of = currentModule.lookupSource(f.getPath()); - if (of != null) { - // Oups, the source is already added, could be ok, could be not, lets check. - if (inLinksrc) { - // So we are collecting sources for linking only. - if (of.isLinkedOnly()) { - // Ouch, this one is also for linking only. Bad. - throw new ProblemException("You have already added the link only file "+fn+" from "+of.file().getPath()); - } - // Ok, the existing source is to be compiled. Thus this link only is redundant - // since all compiled are also linked to. Continue to the next source. - // But we need to add the source, so that it will be visible to linking, - // if not the multi core compile will fail because a JavaCompiler cannot - // find the necessary dependencies for its part of the source. - foundFiles.put(f.getPath(), of); - continue; - } else { - // We are looking for sources to compile, if we find an existing to be compiled - // source with the same name, it is an internal error, since we must - // find the sources to be compiled before we find the sources to be linked to. - throw new ProblemException("Internal error: Double add of file "+fn+" from "+of.file().getPath()); - } - } - Source s = new Source(currentModule, f.getPath(), f, root); - if (inGensrc) s.markAsGenerated(); - if (inLinksrc) { - s.markAsLinkedOnly(); - } - pkg = currentModule.name()+":"+pkg; - foundFiles.put(f.getPath(), s); - currentModule.addSource(pkg, s); + private static List createPathMatchers(FileSystem fs, List patterns) { + List matchers = new ArrayList<>(); + for (String pattern : patterns) { + try { + matchers.add(fs.getPathMatcher("glob:" + pattern)); + } catch (PatternSyntaxException e) { + Log.error("Invalid pattern: " + pattern); + throw e; } } - return currentModule; + return matchers; + } + + private static String packageOfJavaFile(Path sourceRoot, Path javaFile) { + Path javaFileDir = javaFile.getParent(); + Path packageDir = sourceRoot.relativize(javaFileDir); + List separateDirs = new ArrayList<>(); + for (Path pathElement : packageDir) { + separateDirs.add(pathElement.getFileName().toString()); + } + return String.join(".", separateDirs); } - static private void scanDirectory(File dir, int rootPrefix, File root, - Set suffixes, - List excludes, List includes, - List excludeFiles, List includeFiles, - Map foundFiles, - Map foundModules, - Module currentModule, boolean inGensrc, boolean inLinksrc) - throws ProblemException { - - String path = ""; - // Remove the root prefix from the dir path - if (dir.getPath().length() > rootPrefix) { - path = dir.getPath().substring(rootPrefix); - } - // Should this package directory be included and not excluded? - if ((includes==null || includes.isEmpty() || hasMatch(path, includes)) && - (excludes==null || excludes.isEmpty() || !hasMatch(path, excludes))) { - // Add the source files. - currentModule = addFilesInDir(dir, rootPrefix, root, suffixes, true, excludeFiles, includeFiles, - foundFiles, foundModules, currentModule, inGensrc, inLinksrc); - } - - for (File d : dir.listFiles()) { - if (d.isDirectory()) { - // Descend into the directory structure. - scanDirectory(d, rootPrefix, root, suffixes, - excludes, includes, excludeFiles, includeFiles, - foundFiles, foundModules, currentModule, inGensrc, inLinksrc); - } - } + @Override + public String toString() { + return String.format("%s[pkg: %s, name: %s, suffix: %s, file: %s, isGenerated: %b, linkedOnly: %b]", + getClass().getSimpleName(), + pkg, + name, + suffix, + file, + isGenerated, + linkedOnly); } } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java Wed Jul 05 21:13:10 2017 +0200 @@ -230,4 +230,10 @@ Function indexFunction) { return c.stream().collect(Collectors.toMap(indexFunction, o -> o)); } + + public static String fileSuffix(Path file) { + String fileNameStr = file.getFileName().toString(); + int dotIndex = fileNameStr.indexOf('.'); + return dotIndex == -1 ? "" : fileNameStr.substring(dotIndex); + } } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java Wed Jul 05 21:13:10 2017 +0200 @@ -144,77 +144,77 @@ Module current_module = new Module("", ""); modules.put("", current_module); - // Find all sources, use the suffix rules to know which files are sources. - Map sources = new HashMap<>(); + try { + // Find all sources, use the suffix rules to know which files are sources. + Map sources = new HashMap<>(); - // Find the files, this will automatically populate the found modules - // with found packages where the sources are found! - findSourceFiles(options.getSources(), - suffixRules.keySet(), - sources, - modules, - current_module, - options.isDefaultPackagePermitted(), - false); + // Find the files, this will automatically populate the found modules + // with found packages where the sources are found! + findSourceFiles(options.getSources(), + suffixRules.keySet(), + sources, + modules, + current_module, + options.isDefaultPackagePermitted(), + false); - if (sources.isEmpty()) { - Log.error("Found nothing to compile!"); - return RC_FATAL; - } + if (sources.isEmpty()) { + Log.error("Found nothing to compile!"); + return RC_FATAL; + } - // Create a map of all source files that are available for linking. Both -src and - // -sourcepath point to such files. It is possible to specify multiple - // -sourcepath options to enable different filtering rules. If the - // filters are the same for multiple sourcepaths, they may be concatenated - // using :(;). Before sending the list of sourcepaths to javac, they are - // all concatenated. The list created here is used by the SmartFileWrapper to - // make sure only the correct sources are actually available. - // We might find more modules here as well. - Map sources_to_link_to = new HashMap<>(); + // Create a map of all source files that are available for linking. Both -src and + // -sourcepath point to such files. It is possible to specify multiple + // -sourcepath options to enable different filtering rules. If the + // filters are the same for multiple sourcepaths, they may be concatenated + // using :(;). Before sending the list of sourcepaths to javac, they are + // all concatenated. The list created here is used by the SmartFileWrapper to + // make sure only the correct sources are actually available. + // We might find more modules here as well. + Map sources_to_link_to = new HashMap<>(); - List sourceResolutionLocations = new ArrayList<>(); - sourceResolutionLocations.addAll(options.getSources()); - sourceResolutionLocations.addAll(options.getSourceSearchPaths()); - findSourceFiles(sourceResolutionLocations, - Collections.singleton(".java"), - sources_to_link_to, - modules, - current_module, - options.isDefaultPackagePermitted(), - true); + List sourceResolutionLocations = new ArrayList<>(); + sourceResolutionLocations.addAll(options.getSources()); + sourceResolutionLocations.addAll(options.getSourceSearchPaths()); + findSourceFiles(sourceResolutionLocations, + Collections.singleton(".java"), + sources_to_link_to, + modules, + current_module, + options.isDefaultPackagePermitted(), + true); - // Add the set of sources to the build database. - javac_state.now().flattenPackagesSourcesAndArtifacts(modules); - javac_state.now().checkInternalState("checking sources", false, sources); - javac_state.now().checkInternalState("checking linked sources", true, sources_to_link_to); - javac_state.setVisibleSources(sources_to_link_to); + // Add the set of sources to the build database. + javac_state.now().flattenPackagesSourcesAndArtifacts(modules); + javac_state.now().checkInternalState("checking sources", false, sources); + javac_state.now().checkInternalState("checking linked sources", true, sources_to_link_to); + javac_state.setVisibleSources(sources_to_link_to); - int round = 0; - printRound(round); + int round = 0; + printRound(round); - // If there is any change in the source files, taint packages - // and mark the database in need of saving. - javac_state.checkSourceStatus(false); + // If there is any change in the source files, taint packages + // and mark the database in need of saving. + javac_state.checkSourceStatus(false); - // Find all existing artifacts. Their timestamp will match the last modified timestamps stored - // in javac_state, simply because loading of the JavacState will clean out all artifacts - // that do not match the javac_state database. - javac_state.findAllArtifacts(); + // Find all existing artifacts. Their timestamp will match the last modified timestamps stored + // in javac_state, simply because loading of the JavacState will clean out all artifacts + // that do not match the javac_state database. + javac_state.findAllArtifacts(); - // Remove unidentified artifacts from the bin, gensrc and header dirs. - // (Unless we allow them to be there.) - // I.e. artifacts that are not known according to the build database (javac_state). - // For examples, files that have been manually copied into these dirs. - // Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp - // in javac_state) have already been removed when the javac_state was loaded. - if (!options.areUnidentifiedArtifactsPermitted()) { - javac_state.removeUnidentifiedArtifacts(); - } - // Go through all sources and taint all packages that miss artifacts. - javac_state.taintPackagesThatMissArtifacts(); + // Remove unidentified artifacts from the bin, gensrc and header dirs. + // (Unless we allow them to be there.) + // I.e. artifacts that are not known according to the build database (javac_state). + // For examples, files that have been manually copied into these dirs. + // Artifacts with bad timestamps (ie the on disk timestamp does not match the timestamp + // in javac_state) have already been removed when the javac_state was loaded. + if (!options.areUnidentifiedArtifactsPermitted()) { + javac_state.removeUnidentifiedArtifacts(); + } + // Go through all sources and taint all packages that miss artifacts. + javac_state.taintPackagesThatMissArtifacts(); - try { // Check recorded classpath public apis. Taint packages that depend on // classpath classes whose public apis have changed. javac_state.taintPackagesDependingOnChangedClasspathPackages(); @@ -229,8 +229,16 @@ // (Generated sources must always have a package.) Map generated_sources = new HashMap<>(); - Source.scanRoot(Util.pathToFile(options.getGenSrcDir()), Util.set(".java"), null, null, null, null, - generated_sources, modules, current_module, false, true, false); + Source.scanRoot(Util.pathToFile(options.getGenSrcDir()), + Util.set(".java"), + Collections.emptyList(), + Collections.emptyList(), + generated_sources, + modules, + current_module, + false, + true, + false); javac_state.now().flattenPackagesSourcesAndArtifacts(modules); // Recheck the the source files and their timestamps again. javac_state.checkSourceStatus(true); @@ -254,7 +262,10 @@ printRound(round); // Clean out artifacts in tainted packages. javac_state.deleteClassArtifactsInTaintedPackages(); - again = javac_state.performJavaCompilations(compilationService, options, recently_compiled, rc); + again = javac_state.performJavaCompilations(compilationService, + options, + recently_compiled, + rc); if (!rc[0]) { Log.debug("Compilation failed."); break; @@ -344,7 +355,8 @@ Map foundModules, Module currentModule, boolean permitSourcesInDefaultPackage, - boolean inLinksrc) { + boolean inLinksrc) + throws IOException { for (SourceLocation source : sourceLocations) { source.findSourceFiles(sourceTypes, diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java Wed Jul 05 21:13:10 2017 +0200 @@ -93,7 +93,7 @@ CLASSPATH.processMatching(iter, helper); } }, - X("-x", "Exclude directory from the subsequent source directory") { + X("-x", "Exclude files matching the given pattern") { @Override protected void processMatching(ArgumentIterator iter, OptionHelper helper) { String pattern = getFilePatternArg(iter, helper); @@ -101,7 +101,7 @@ helper.exclude(pattern); } }, - I("-i", "Include only the given directory from the subsequent source directory") { + I("-i", "Include only files matching the given pattern") { @Override protected void processMatching(ArgumentIterator iter, OptionHelper helper) { String pattern = getFilePatternArg(iter, helper); @@ -109,22 +109,6 @@ helper.include(pattern); } }, - XF("-xf", "Exclude a given file") { - @Override - protected void processMatching(ArgumentIterator iter, OptionHelper helper) { - String pattern = getFilePatternArg(iter, helper); - if (pattern != null) - helper.excludeFile(pattern); - } - }, - IF("-if", "Include only the given file") { - @Override - protected void processMatching(ArgumentIterator iter, OptionHelper helper) { - String pattern = getFilePatternArg(iter, helper); - if (pattern != null) - helper.includeFile(pattern); - } - }, TR("-tr", "Translate resources") { @Override protected void processMatching(ArgumentIterator iter, OptionHelper helper) { @@ -338,7 +322,7 @@ String getFilePatternArg(ArgumentIterator iter, OptionHelper helper) { if (!iter.hasNext()) { - helper.reportError(arg + " must be followed by a file or directory pattern."); + helper.reportError(arg + " must be followed by a glob pattern."); return null; } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/OptionHelper.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/OptionHelper.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/OptionHelper.java Wed Jul 05 21:13:10 2017 +0200 @@ -53,12 +53,6 @@ /** Record a package inclusion pattern */ public abstract void include(String incl); - /** Record a file exclusion */ - public abstract void excludeFile(String exclFile); - - /** Record a file inclusion */ - public abstract void includeFile(String inclFile); - /** Record a root of sources to be compiled */ public abstract void sourceRoots(List path); diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Options.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Options.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Options.java Wed Jul 05 21:13:10 2017 +0200 @@ -220,8 +220,6 @@ for (SourceLocation sl : locs) { for (String pkg : sl.includes) addArg(Option.I, pkg); for (String pkg : sl.excludes) addArg(Option.X, pkg); - for (String f : sl.excludedFiles) addArg(Option.XF, f); - for (String f : sl.includedFiles) addArg(Option.IF, f); addArg(opt, sl.getPath()); } } @@ -380,18 +378,6 @@ } @Override - public void excludeFile(String exclFilePattern) { - exclFilePattern = Util.normalizeDriveLetter(exclFilePattern); - excludeFiles.add(exclFilePattern); - } - - @Override - public void includeFile(String inclFilePattern) { - inclFilePattern = Util.normalizeDriveLetter(inclFilePattern); - includeFiles.add(inclFilePattern); - } - - @Override public void addTransformer(String suffix, Transformer tr) { if (trRules.containsKey(suffix)) { reportError("More than one transformer specified for " + @@ -519,9 +505,7 @@ result.add(new SourceLocation( path, includes, - excludes, - includeFiles, - excludeFiles)); + excludes)); } resetFilters(); return result; diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/SourceLocation.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/SourceLocation.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/SourceLocation.java Wed Jul 05 21:13:10 2017 +0200 @@ -25,11 +25,13 @@ package com.sun.tools.sjavac.options; +import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Map; import java.util.Set; +import com.sun.tools.sjavac.Log; import com.sun.tools.sjavac.Module; import com.sun.tools.sjavac.ProblemException; import com.sun.tools.sjavac.Source; @@ -49,18 +51,14 @@ private Path path; // Package include / exclude patterns and file includes / excludes. - List includes, excludes, includedFiles, excludedFiles; + List includes, excludes; public SourceLocation(Path path, List includes, - List excludes, - List includedFiles, - List excludedFiles) { + List excludes) { this.path = path; this.includes = includes; this.excludes = excludes; - this.includedFiles = includedFiles; - this.excludedFiles = excludedFiles; } @@ -81,17 +79,23 @@ Map foundModules, Module currentModule, boolean permitSourcesInDefaultPackage, - boolean inLinksrc) { + boolean inLinksrc) + throws IOException { try { - Source.scanRoot(path.toFile(), suffixes, excludes, includes, - excludedFiles, includedFiles, foundFiles, foundModules, - currentModule, permitSourcesInDefaultPackage, false, - inLinksrc); + Source.scanRoot(path.toFile(), + suffixes, + excludes, + includes, + foundFiles, + foundModules, + currentModule, + permitSourcesInDefaultPackage, + false, + inLinksrc); } catch (ProblemException e) { e.printStackTrace(); } } - /** Get the root directory of this source location */ public Path getPath() { return path; @@ -107,14 +111,9 @@ return excludes; } - /** Get the file include patterns */ - public List getIncludedFiles() { - return includedFiles; + @Override + public String toString() { + return String.format("%s[\"%s\", includes: %s, excludes: %s]", + getClass().getSimpleName(), path, includes, excludes); } - - /** Get the file exclude patterns */ - public List getExcludedFiles() { - return excludedFiles; - } - } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,11 +174,20 @@ /** * Delete the port file. */ - public void delete() throws IOException { + public void delete() throws IOException, InterruptedException { // Access to file must be closed before deleting. rwfile.close(); - // Now delete. + file.delete(); + + // Wait until file has been deleted (deletes are asynchronous on Windows!) otherwise we + // might shutdown the server and prevent another one from starting. + for (int i = 0; i < 10 && file.exists(); i++) { + Thread.sleep(1000); + } + if (file.exists()) { + throw new IOException("Failed to delete file."); + } } /** diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -279,7 +279,7 @@ // failed connection attempts try { portFile.delete(); - } catch (IOException e) { + } catch (IOException | InterruptedException e) { e.printStackTrace(theLog); } try { diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -248,7 +248,7 @@ for (ProgramElementDoc element : list) { Object key = getMemberKey(element); Map memberLevelMap = memberNameMap.get(key); - if (level.equals(memberLevelMap.get(element))) + if (memberLevelMap != null && level.equals(memberLevelMap.get(element))) memberLevelMap.remove(element); } } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java Wed Jul 05 21:13:10 2017 +0200 @@ -28,6 +28,9 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -35,7 +38,9 @@ import java.util.ArrayList; import java.util.List; + import static jdk.internal.jshell.remote.RemoteCodes.*; + import java.util.Map; import java.util.TreeMap; @@ -59,7 +64,10 @@ void commandLoop(Socket socket) throws IOException { // in before out -- so we don't hang the controlling process ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); - ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); + OutputStream socketOut = socket.getOutputStream(); + System.setOut(new PrintStream(new MultiplexingOutputStream("out", socketOut), true)); + System.setErr(new PrintStream(new MultiplexingOutputStream("err", socketOut), true)); + ObjectOutputStream out = new ObjectOutputStream(new MultiplexingOutputStream("command", socketOut)); while (true) { int cmd = in.readInt(); switch (cmd) { @@ -260,4 +268,64 @@ } return sb.toString(); } + + private static final class MultiplexingOutputStream extends OutputStream { + + private static final int PACKET_SIZE = 127; + + private final byte[] name; + private final OutputStream delegate; + + public MultiplexingOutputStream(String name, OutputStream delegate) { + try { + this.name = name.getBytes("UTF-8"); + this.delegate = delegate; + } catch (UnsupportedEncodingException ex) { + throw new IllegalStateException(ex); //should not happen + } + } + + @Override + public void write(int b) throws IOException { + synchronized (delegate) { + delegate.write(name.length); //assuming the len is small enough to fit into byte + delegate.write(name); + delegate.write(1); + delegate.write(b); + delegate.flush(); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + synchronized (delegate) { + int i = 0; + while (len > 0) { + int size = Math.min(PACKET_SIZE, len); + + delegate.write(name.length); //assuming the len is small enough to fit into byte + delegate.write(name); + delegate.write(size); + delegate.write(b, off + i, size); + i += size; + len -= size; + } + + delegate.flush(); + } + } + + @Override + public void flush() throws IOException { + super.flush(); + delegate.flush(); + } + + @Override + public void close() throws IOException { + super.close(); + delegate.close(); + } + + } } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,3 +1,4 @@ + /* * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -90,8 +91,10 @@ import java.util.Optional; import java.util.ResourceBundle; import java.util.Spliterators; +import java.util.function.Function; import java.util.function.Supplier; import static java.util.stream.Collectors.toList; +import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; /** * Command line REPL tool for Java using the JShell API. @@ -102,6 +105,7 @@ private static final Pattern LINEBREAK = Pattern.compile("\\R"); private static final Pattern HISTORY_ALL_START_FILENAME = Pattern.compile( "((?(all|history|start))(\\z|\\p{javaWhitespace}+))?(?.*)"); + private static final String RECORD_SEPARATOR = "\u241E"; final InputStream cmdin; final PrintStream cmdout; @@ -150,9 +154,14 @@ private String cmdlineStartup = null; private String editor = null; - static final Preferences PREFS = Preferences.userRoot().node("tool/REPL"); + // Commands and snippets which should be replayed + private List replayableHistory; + private List replayableHistoryPrevious; + + static final Preferences PREFS = Preferences.userRoot().node("tool/JShell"); static final String STARTUP_KEY = "STARTUP"; + static final String REPLAY_RESTORE_KEY = "REPLAY_RESTORE"; static final String DEFAULT_STARTUP = "\n" + @@ -165,11 +174,14 @@ "import java.util.regex.*;\n" + "void printf(String format, Object... args) { System.out.printf(format, args); }\n"; - // Tool id (tid) mapping + // Tool id (tid) mapping: the three name spaces NameSpace mainNamespace; NameSpace startNamespace; NameSpace errorNamespace; + + // Tool id (tid) mapping: the current name spaces NameSpace currentNameSpace; + Map mapSnippet; void debug(String format, Object... args) { @@ -252,6 +264,12 @@ private void start(IOContext in, List loadList) { resetState(); // Initialize + // Read replay history from last jshell session into previous history + String prevReplay = PREFS.get(REPLAY_RESTORE_KEY, null); + if (prevReplay != null) { + replayableHistoryPrevious = Arrays.asList(prevReplay.split(RECORD_SEPARATOR)); + } + for (String loadFile : loadList) { cmdOpen(loadFile); } @@ -370,6 +388,10 @@ mapSnippet = new LinkedHashMap<>(); currentNameSpace = startNamespace; + // Reset the replayable history, saving the old for restore + replayableHistoryPrevious = replayableHistory; + replayableHistory = new ArrayList<>(); + state = JShell.builder() .in(userin) .out(userout) @@ -382,7 +404,8 @@ analysis = state.sourceCodeAnalysis(); shutdownSubscription = state.onShutdown((JShell deadState) -> { if (deadState == state) { - hard("State engine terminated. See /history"); + hard("State engine terminated."); + hard("Restore definitions with: /reload restore"); live = false; } }); @@ -392,7 +415,6 @@ state.addToClasspath(cmdlineClasspath); } - String start; if (cmdlineStartup == null) { start = PREFS.get(STARTUP_KEY, ""); @@ -431,7 +453,7 @@ String incomplete = ""; while (live) { String prompt; - if (in.interactiveOutput() && displayPrompt) { + if (displayPrompt) { prompt = testPrompt ? incomplete.isEmpty() ? "\u0005" //ENQ @@ -480,6 +502,12 @@ } } + private void addToReplayHistory(String s) { + if (currentNameSpace == mainNamespace) { + replayableHistory.add(s); + } + } + private String processSourceCatchingReset(String src) { try { input.beforeUserCode(); @@ -516,7 +544,12 @@ fluff("Type /help for help."); } } else if (candidates.length == 1) { - candidates[0].run.accept(arg); + Command command = candidates[0]; + + // If comand was successful and is of a replayable kind, add it the replayable history + if (command.run.apply(arg) && command.kind == CommandKind.REPLAY) { + addToReplayHistory((command.command + " " + arg).trim()); + } } else { hard("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); fluff("Type /help for help."); @@ -546,15 +579,15 @@ public final String command; public final String params; public final String description; - public final Consumer run; + public final Function run; public final CompletionProvider completions; public final CommandKind kind; - public Command(String command, String params, String description, Consumer run, CompletionProvider completions) { + public Command(String command, String params, String description, Function run, CompletionProvider completions) { this(command, params, description, run, completions, CommandKind.NORMAL); } - public Command(String command, String params, String description, Consumer run, CompletionProvider completions, CommandKind kind) { + public Command(String command, String params, String description, Function run, CompletionProvider completions, CommandKind kind) { this.command = command; this.params = params; this.description = description; @@ -571,6 +604,7 @@ enum CommandKind { NORMAL, + REPLAY, HIDDEN, HELP_ONLY; } @@ -602,6 +636,7 @@ private static final CompletionProvider EMPTY_COMPLETION_PROVIDER = new FixedCompletionProvider(); private static final CompletionProvider KEYWORD_COMPLETION_PROVIDER = new FixedCompletionProvider("all ", "start ", "history "); + private static final CompletionProvider RELOAD_OPTIONS_COMPLETION_PROVIDER = new FixedCompletionProvider("restore", "quiet"); private static final CompletionProvider FILE_COMPLETION_PROVIDER = fileCompletions(p -> true); private final Map commands = new LinkedHashMap<>(); private void registerCommand(Command cmd) { @@ -674,6 +709,16 @@ }; } + private static CompletionProvider reloadCompletion() { + return (code, cursor, anchor) -> { + List result = new ArrayList<>(); + int pastSpace = code.indexOf(' ') + 1; // zero if no space + result.addAll(RELOAD_OPTIONS_COMPLETION_PROVIDER.completionSuggestions(code.substring(pastSpace), cursor - pastSpace, anchor)); + anchor[0] += pastSpace; + return result; + }; + } + // Table of commands -- with command forms, argument kinds, help message, implementation, ... { @@ -688,7 +733,8 @@ editCompletion())); registerCommand(new Command("/drop", "", "delete a source entry referenced by name or id", arg -> cmdDrop(arg), - editCompletion())); + editCompletion(), + CommandKind.REPLAY)); registerCommand(new Command("/save", "[all|history|start] ", "save: - current source;\n" + " all - source including overwritten, failed, and start-up code;\n" + " history - editing history;\n" + @@ -716,6 +762,9 @@ registerCommand(new Command("/reset", null, "reset everything in the REPL", arg -> cmdReset(), EMPTY_COMPLETION_PROVIDER)); + registerCommand(new Command("/reload", "[restore] [quiet]", "reset and replay relevant history -- current or previous (restore)", + arg -> cmdReload(arg), + reloadCompletion())); registerCommand(new Command("/feedback", "", "feedback information: off, concise, normal, verbose, default, or ?", arg -> cmdFeedback(arg), new FixedCompletionProvider("off", "concise", "normal", "verbose", "default", "?"))); @@ -724,7 +773,8 @@ EMPTY_COMPLETION_PROVIDER)); registerCommand(new Command("/classpath", "", "add a path to the classpath", arg -> cmdClasspath(arg), - classPathCompletion())); + classPathCompletion(), + CommandKind.REPLAY)); registerCommand(new Command("/history", null, "history of what you have typed", arg -> cmdHistory(), EMPTY_COMPLETION_PROVIDER)); @@ -801,25 +851,29 @@ // --- Command implementations --- - void cmdSetEditor(String arg) { + boolean cmdSetEditor(String arg) { if (arg.isEmpty()) { hard("/seteditor requires a path argument"); + return false; } else { editor = arg; fluff("Editor set to: %s", arg); + return true; } } - void cmdClasspath(String arg) { + boolean cmdClasspath(String arg) { if (arg.isEmpty()) { hard("/classpath requires a path argument"); + return false; } else { state.addToClasspath(toPathResolvingUserHome(arg).toString()); fluff("Path %s added to classpath", arg); + return true; } } - void cmdDebug(String arg) { + boolean cmdDebug(String arg) { if (arg.isEmpty()) { debug = !debug; InternalDebugControl.setDebugFlags(state, debug ? InternalDebugControl.DBG_GEN : 0); @@ -860,20 +914,26 @@ default: hard("Unknown debugging option: %c", ch); fluff("Use: 0 r g f c d"); - break; + return false; } } InternalDebugControl.setDebugFlags(state, flags); } + return true; } - private void cmdExit() { + private boolean cmdExit() { regenerateOnDeath = false; live = false; + if (!replayableHistory.isEmpty()) { + PREFS.put(REPLAY_RESTORE_KEY, replayableHistory.stream().reduce( + (a, b) -> a + RECORD_SEPARATOR + b).get()); + } fluff("Goodbye\n"); + return true; } - private void cmdFeedback(String arg) { + private boolean cmdFeedback(String arg) { switch (arg) { case "": case "d": @@ -905,12 +965,13 @@ hard(" default"); hard("You may also use just the first letter, for example: /f c"); hard("In interactive mode 'default' is the same as 'normal', from a file it is the same as 'off'"); - return; + return false; } fluff("Feedback mode: %s", feedback.name().toLowerCase()); + return true; } - void cmdHelp() { + boolean cmdHelp() { int synopsisLen = 0; Map synopsis2Description = new LinkedHashMap<>(); for (Command cmd : new LinkedHashSet<>(commands.values())) { @@ -936,14 +997,16 @@ cmdout.println("Supported shortcuts include:"); cmdout.println(" -- show possible completions for the current text"); cmdout.println("Shift- -- for current method or constructor invocation, show a synopsis of the method/constructor"); + return true; } - private void cmdHistory() { + private boolean cmdHistory() { cmdout.println(); for (String s : input.currentSessionHistory()) { // No number prefix, confusing with snippet ids cmdout.printf("%s\n", s); } + return true; } /** @@ -1010,23 +1073,23 @@ } } - private void cmdDrop(String arg) { + private boolean cmdDrop(String arg) { if (arg.isEmpty()) { hard("In the /drop argument, please specify an import, variable, method, or class to drop."); hard("Specify by id or name. Use /list to see ids. Use /reset to reset all state."); - return; + return false; } Stream stream = argToSnippets(arg, false); if (stream == null) { hard("No definition or id named %s found. See /classes, /methods, /vars, or /list", arg); - return; + return false; } List snippets = stream .filter(sn -> state.status(sn).isActive && sn instanceof PersistentSnippet) .collect(toList()); if (snippets.isEmpty()) { hard("The argument did not specify an active import, variable, method, or class to drop."); - return; + return false; } if (snippets.size() > 1) { hard("The argument references more than one import, variable, method, or class."); @@ -1034,17 +1097,18 @@ for (Snippet sn : snippets) { cmdout.printf("%4s : %s\n", sn.id(), sn.source().replace("\n", "\n ")); } - return; + return false; } PersistentSnippet psn = (PersistentSnippet) snippets.get(0); state.drop(psn).forEach(this::handleEvent); + return true; } - private void cmdEdit(String arg) { + private boolean cmdEdit(String arg) { Stream stream = argToSnippets(arg, true); if (stream == null) { hard("No definition or id named %s found. See /classes, /methods, /vars, or /list", arg); - return; + return false; } Set srcSet = new LinkedHashSet<>(); stream.forEachOrdered(sn -> { @@ -1078,6 +1142,7 @@ } else { ExternalEditor.edit(editor, errorHandler, src, saveHandler, input); } + return true; } //where // receives editor requests to save @@ -1135,10 +1200,9 @@ } } - private void cmdList(String arg) { + private boolean cmdList(String arg) { if (arg.equals("history")) { - cmdHistory(); - return; + return cmdHistory(); } Stream stream = argToSnippets(arg, true); if (stream == null) { @@ -1148,7 +1212,7 @@ } else { hard("No definition or id named %s found. There are no active definitions.", arg); } - return; + return false; } // prevent double newline on empty list @@ -1160,38 +1224,72 @@ } cmdout.printf("%4s : %s\n", sn.id(), sn.source().replace("\n", "\n ")); }); + return true; } - private void cmdOpen(String filename) { + private boolean cmdOpen(String filename) { if (filename.isEmpty()) { hard("The /open command requires a filename argument."); + return false; } else { try { run(new FileScannerIOContext(toPathResolvingUserHome(filename).toString())); } catch (FileNotFoundException e) { hard("File '%s' is not found: %s", filename, e.getMessage()); + return false; } catch (Exception e) { hard("Exception while reading file: %s", e); + return false; } } + return true; } - private void cmdPrompt() { + private boolean cmdPrompt() { displayPrompt = !displayPrompt; fluff("Prompt will %sdisplay. Use /prompt to toggle.", displayPrompt ? "" : "NOT "); concise("Prompt: %s", displayPrompt ? "on" : "off"); + return true; + } + + private boolean cmdReset() { + live = false; + fluff("Resetting state."); + return true; } - private void cmdReset() { - live = false; - fluff("Resetting state."); + private boolean cmdReload(String arg) { + Iterable history = replayableHistory; + boolean echo = true; + if (arg.length() > 0) { + if ("restore".startsWith(arg)) { + if (replayableHistoryPrevious == null) { + hard("No previous history to restore\n", arg); + return false; + } + history = replayableHistoryPrevious; + } else if ("quiet".startsWith(arg)) { + echo = false; + } else { + hard("Invalid argument to reload command: %s\nUse 'restore', 'quiet', or no argument\n", arg); + return false; + } + } + fluff("Restarting and restoring %s.", + history == replayableHistoryPrevious + ? "from previous state" + : "state"); + resetState(); + run(new ReloadIOContext(history, + echo? cmdout : null)); + return true; } - private void cmdSave(String arg_filename) { + private boolean cmdSave(String arg_filename) { Matcher mat = HISTORY_ALL_START_FILENAME.matcher(arg_filename); if (!mat.find()) { hard("Malformed argument to the /save command: %s", arg_filename); - return; + return false; } boolean useHistory = false; String saveAll = ""; @@ -1211,7 +1309,7 @@ String filename = mat.group("filename"); if (filename == null ||filename.isEmpty()) { hard("The /save command requires a filename argument."); - return; + return false; } try (BufferedWriter writer = Files.newBufferedWriter(toPathResolvingUserHome(filename), Charset.defaultCharset(), @@ -1234,12 +1332,15 @@ } } catch (FileNotFoundException e) { hard("File '%s' for save is not accessible: %s", filename, e.getMessage()); + return false; } catch (Exception e) { hard("Exception while saving: %s", e); + return false; } + return true; } - private void cmdSetStart(String filename) { + private boolean cmdSetStart(String filename) { if (filename.isEmpty()) { hard("The /setstart command requires a filename argument."); } else { @@ -1249,30 +1350,36 @@ PREFS.put(STARTUP_KEY, init); } catch (AccessDeniedException e) { hard("File '%s' for /setstart is not accessible.", filename); + return false; } catch (NoSuchFileException e) { hard("File '%s' for /setstart is not found.", filename); + return false; } catch (Exception e) { hard("Exception while reading start set file: %s", e); + return false; } } + return true; } - private void cmdVars() { + private boolean cmdVars() { for (VarSnippet vk : state.variables()) { String val = state.status(vk) == Status.VALID ? state.varValue(vk) : "(not-active)"; hard(" %s %s = %s", vk.typeName(), vk.name(), val); } + return true; } - private void cmdMethods() { + private boolean cmdMethods() { for (MethodSnippet mk : state.methods()) { hard(" %s %s", mk.name(), mk.signature()); } + return true; } - private void cmdClasses() { + private boolean cmdClasses() { for (TypeDeclSnippet ck : state.types()) { String kind; switch (ck.subKind()) { @@ -1295,15 +1402,17 @@ } hard(" %s %s", kind, ck.name()); } + return true; } - private void cmdImports() { + private boolean cmdImports() { state.imports().forEach(ik -> { hard(" import %s%s", ik.isStatic() ? "static " : "", ik.fullname()); }); + return true; } - private void cmdUseHistoryEntry(int index) { + private boolean cmdUseHistoryEntry(int index) { List keys = state.snippets(); if (index < 0) index += keys.size(); @@ -1313,7 +1422,9 @@ rerunSnippet(keys.get(index)); } else { hard("Cannot find snippet %d", index + 1); + return false; } + return true; } private boolean rerunHistoryEntryById(String id) { @@ -1357,7 +1468,7 @@ } } - for (String line : diag.getMessage(null).split("\\r?\\n")) { + for (String line : diag.getMessage(null).split("\\r?\\n")) { // TODO: Internationalize if (!line.trim().startsWith("location:")) { hard("%s%s", padding, line); } @@ -1425,10 +1536,24 @@ private boolean processCompleteSource(String source) throws IllegalStateException { debug("Compiling: %s", source); boolean failed = false; + boolean isActive = false; List events = state.eval(source); for (SnippetEvent e : events) { + // Report the event, recording failure failed |= handleEvent(e); + + // If any main snippet is active, this should be replayable + // also ignore var value queries + isActive |= e.causeSnippet() == null && + e.status().isActive && + e.snippet().subKind() != VAR_VALUE_SUBKIND; } + // If this is an active snippet and it didn't cause the backend to die, + // add it to the replayable history + if (isActive && live) { + addToReplayHistory(source); + } + return failed; } @@ -1784,31 +1909,11 @@ } } -class ScannerIOContext extends IOContext { - - private final Scanner scannerIn; - private final PrintStream pStream; - - public ScannerIOContext(Scanner scannerIn, PrintStream pStream) { - this.scannerIn = scannerIn; - this.pStream = pStream; - } - - @Override - public String readLine(String prompt, String prefix) { - if (pStream != null && prompt != null) { - pStream.print(prompt); - } - if (scannerIn.hasNextLine()) { - return scannerIn.nextLine(); - } else { - return null; - } - } +abstract class NonInteractiveIOContext extends IOContext { @Override public boolean interactiveOutput() { - return true; + return false; } @Override @@ -1817,11 +1922,6 @@ } @Override - public void close() { - scannerIn.close(); - } - - @Override public boolean terminalEditorRunning() { return false; } @@ -1847,19 +1947,62 @@ } } +class ScannerIOContext extends NonInteractiveIOContext { + private final Scanner scannerIn; + + ScannerIOContext(Scanner scannerIn) { + this.scannerIn = scannerIn; + } + + @Override + public String readLine(String prompt, String prefix) { + if (scannerIn.hasNextLine()) { + return scannerIn.nextLine(); + } else { + return null; + } + } + + @Override + public void close() { + scannerIn.close(); + } +} + class FileScannerIOContext extends ScannerIOContext { - public FileScannerIOContext(String fn) throws FileNotFoundException { + FileScannerIOContext(String fn) throws FileNotFoundException { this(new FileReader(fn)); } - public FileScannerIOContext(Reader rdr) throws FileNotFoundException { - super(new Scanner(rdr), null); + FileScannerIOContext(Reader rdr) throws FileNotFoundException { + super(new Scanner(rdr)); + } +} + +class ReloadIOContext extends NonInteractiveIOContext { + private final Iterator it; + private final PrintStream echoStream; + + ReloadIOContext(Iterable history, PrintStream echoStream) { + this.it = history.iterator(); + this.echoStream = echoStream; } @Override - public boolean interactiveOutput() { - return false; + public String readLine(String prompt, String prefix) { + String s = it.hasNext() + ? it.next() + : null; + if (echoStream != null && s != null) { + String p = "-: "; + String p2 = "\n "; + echoStream.printf("%s%s\n", p, s.replace("\n", p2)); + } + return s; + } + + @Override + public void close() { } } - diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java Wed Jul 05 21:13:10 2017 +0200 @@ -26,9 +26,12 @@ package jdk.jshell; import static jdk.internal.jshell.remote.RemoteCodes.*; +import java.io.DataInputStream; +import java.io.InputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import com.sun.jdi.*; @@ -69,7 +72,9 @@ socket = listener.accept(); // out before in -- match remote creation so we don't hang out = new ObjectOutputStream(socket.getOutputStream()); - in = new ObjectInputStream(socket.getInputStream()); + PipeInputStream commandIn = new PipeInputStream(); + new DemultiplexInput(socket.getInputStream(), commandIn, proc.out, proc.err).start(); + in = new ObjectInputStream(commandIn); } } @@ -117,11 +122,13 @@ String result = in.readUTF(); return result; } - } catch (EOFException ex) { - env.shutdown(); } catch (IOException | ClassNotFoundException ex) { - proc.debug(DBG_GEN, "Exception on remote invoke: %s\n", ex); - return "Execution failure: " + ex.getMessage(); + if (!env.connection().isRunning()) { + env.shutdown(); + } else { + proc.debug(DBG_GEN, "Exception on remote invoke: %s\n", ex); + return "Execution failure: " + ex.getMessage(); + } } finally { synchronized (STOP_LOCK) { userCodeRunning = false; @@ -310,4 +317,112 @@ } } } + + private final class DemultiplexInput extends Thread { + + private final DataInputStream delegate; + private final PipeInputStream command; + private final PrintStream out; + private final PrintStream err; + + public DemultiplexInput(InputStream input, + PipeInputStream command, + PrintStream out, + PrintStream err) { + super("output reader"); + this.delegate = new DataInputStream(input); + this.command = command; + this.out = out; + this.err = err; + } + + public void run() { + try { + while (true) { + int nameLen = delegate.read(); + if (nameLen == (-1)) + break; + byte[] name = new byte[nameLen]; + DemultiplexInput.this.delegate.readFully(name); + int dataLen = delegate.read(); + byte[] data = new byte[dataLen]; + DemultiplexInput.this.delegate.readFully(data); + switch (new String(name, "UTF-8")) { + case "err": + err.write(data); + break; + case "out": + out.write(data); + break; + case "command": + for (byte b : data) { + command.write(Byte.toUnsignedInt(b)); + } + break; + } + } + } catch (IOException ex) { + proc.debug(ex, "Failed reading output"); + } finally { + command.close(); + } + } + + } + + public static final class PipeInputStream extends InputStream { + public static final int INITIAL_SIZE = 128; + + private int[] buffer = new int[INITIAL_SIZE]; + private int start; + private int end; + private boolean closed; + + @Override + public synchronized int read() { + while (start == end) { + if (closed) { + return -1; + } + try { + wait(); + } catch (InterruptedException ex) { + //ignore + } + } + try { + return buffer[start]; + } finally { + start = (start + 1) % buffer.length; + } + } + + public synchronized void write(int b) { + if (closed) + throw new IllegalStateException("Already closed."); + int newEnd = (end + 1) % buffer.length; + if (newEnd == start) { + //overflow: + int[] newBuffer = new int[buffer.length * 2]; + int rightPart = (end > start ? end : buffer.length) - start; + int leftPart = end > start ? 0 : start - 1; + System.arraycopy(buffer, start, newBuffer, 0, rightPart); + System.arraycopy(buffer, 0, newBuffer, rightPart, leftPart); + buffer = newBuffer; + start = 0; + end = rightPart + leftPart; + newEnd = end + 1; + } + buffer[end] = b; + end = newEnd; + notifyAll(); + } + + @Override + public synchronized void close() { + closed = true; + notifyAll(); + } + + } } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java Wed Jul 05 21:13:10 2017 +0200 @@ -133,7 +133,7 @@ return vm; } - boolean setConnectorArg(String name, String value) { + synchronized boolean setConnectorArg(String name, String value) { /* * Too late if the connection already made */ @@ -165,7 +165,7 @@ } } - boolean isOpen() { + synchronized boolean isOpen() { return (vm != null); } @@ -173,13 +173,17 @@ return (connector instanceof LaunchingConnector); } - public void disposeVM() { + synchronized boolean isRunning() { + return process != null && process.isAlive(); + } + + public synchronized void disposeVM() { try { if (vm != null) { vm.dispose(); // This could NPE, so it is caught below vm = null; } - } catch (VMDisconnectedException | NullPointerException ex) { + } catch (VMDisconnectedException ex) { // Ignore if already closed } finally { if (process != null) { diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java Wed Jul 05 21:13:10 2017 +0200 @@ -182,9 +182,9 @@ return null; } - @Override - public String toString() { - return "WrappedDiagnostic(" + getMessage(null) + ":" + getPosition() + ")"; - } + @Override + public String toString() { + return "WrappedDiagnostic(" + getMessage(null) + ":" + getPosition() + ")"; + } } } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java Wed Jul 05 21:13:10 2017 +0200 @@ -33,7 +33,6 @@ import com.sun.tools.javac.util.Context; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import javax.tools.Diagnostic; import javax.tools.DiagnosticCollector; @@ -395,7 +394,7 @@ LinkedHashMap diagMap = new LinkedHashMap<>(); for (Diagnostic in : diagnostics.getDiagnostics()) { Diag d = diag(in); - String uniqueKey = d.getCode() + ":" + d.getPosition() + ":" + d.getMessage(null); + String uniqueKey = d.getCode() + ":" + d.getPosition() + ":" + d.getMessage(PARSED_LOCALE); diagMap.put(uniqueKey, d); } diags = new DiagList(diagMap.values()); @@ -410,7 +409,7 @@ String shortErrorMessage() { StringBuilder sb = new StringBuilder(); for (Diag diag : getDiagnostics()) { - for (String line : diag.getMessage(null).split("\\r?\\n")) { + for (String line : diag.getMessage(PARSED_LOCALE).split("\\r?\\n")) { if (!line.trim().startsWith("location:")) { sb.append(line); } @@ -422,7 +421,7 @@ void debugPrintDiagnostics(String src) { for (Diag diag : getDiagnostics()) { state.debug(DBG_GEN, "ERROR --\n"); - for (String line : diag.getMessage(null).split("\\r?\\n")) { + for (String line : diag.getMessage(PARSED_LOCALE).split("\\r?\\n")) { if (!line.trim().startsWith("location:")) { state.debug(DBG_GEN, "%s\n", line); } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java Wed Jul 05 21:13:10 2017 +0200 @@ -50,6 +50,7 @@ import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; import static jdk.jshell.Snippet.Status.REJECTED; import static jdk.jshell.Snippet.Status.VALID; +import static jdk.jshell.Util.PARSED_LOCALE; import static jdk.jshell.Util.expunge; /** @@ -456,7 +457,7 @@ for (Diag diag : diags) { if (diag.isError()) { if (diag.isResolutionError()) { - String m = diag.getMessage(null); + String m = diag.getMessage(PARSED_LOCALE); int symPos = m.indexOf(RESOLVE_ERROR_SYMBOL); if (symPos >= 0) { m = m.substring(symPos + RESOLVE_ERROR_SYMBOL.length()); diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java Wed Jul 05 21:13:10 2017 +0200 @@ -25,6 +25,7 @@ package jdk.jshell; +import java.util.Locale; import java.util.stream.Stream; import java.util.stream.StreamSupport; import javax.lang.model.element.Name; @@ -40,6 +41,8 @@ static final String REPL_CLASS_PREFIX = "$REPL"; static final String REPL_DOESNOTMATTER_CLASS_NAME = REPL_CLASS_PREFIX+"00DOESNOTMATTER"; + static final Locale PARSED_LOCALE = Locale.ROOT; + static boolean isDoIt(Name name) { return isDoIt(name.toString()); } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/jdk/jshell/ReplToolTesting.java --- a/langtools/test/jdk/jshell/ReplToolTesting.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/jdk/jshell/ReplToolTesting.java Wed Jul 05 21:13:10 2017 +0200 @@ -152,13 +152,13 @@ } public String getCommandOutput() { - String s = cmdout.toString(); + String s = normalizeLineEndings(cmdout.toString()); cmdout.reset(); return s; } public String getCommandErrorOutput() { - String s = cmderr.toString(); + String s = normalizeLineEndings(cmderr.toString()); cmderr.reset(); return s; } @@ -168,13 +168,13 @@ } public String getUserOutput() { - String s = userout.toString(); + String s = normalizeLineEndings(userout.toString()); userout.reset(); return s; } public String getUserErrorOutput() { - String s = usererr.toString(); + String s = normalizeLineEndings(usererr.toString()); usererr.reset(); return s; } @@ -461,6 +461,10 @@ } } + private String normalizeLineEndings(String text) { + return text.replace(System.getProperty("line.separator"), "\n"); + } + public static abstract class MemberInfo { public final String source; public final String type; diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/jdk/jshell/T8146368/JShellTest8146368.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/T8146368/JShellTest8146368.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8146368 + * @summary Test Smashing Error when user language is Japanese + * @library /tools/lib /jdk/jshell + * @build KullaTesting + * @run testng/othervm -Duser.language=ja JShellTest8146368 + */ + +import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; +import org.testng.annotations.Test; + +@Test +public class JShellTest8146368 extends KullaTesting { + public void test() { + assertEval("class A extends B {}", added(RECOVERABLE_NOT_DEFINED)); + assertEval("und m() { return new und(); }", added(RECOVERABLE_NOT_DEFINED)); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8146368 + * @summary Test Smashing Error when user language is Japanese + * @library /tools/lib /jdk/jshell + * @build ReplToolTesting + * @run testng/othervm -Duser.language=ja JShellToolTest8146368 + */ + +import org.testng.annotations.Test; + +@Test +public class JShellToolTest8146368 extends ReplToolTesting { + public void test() { + test( + a -> assertCommand(a, "class A extends B {}", "| Added class A, however, it cannot be referenced until class B is declared\n"), + a -> assertCommand(a, "und m() { return new und(); }", "| Added method m(), however, it cannot be referenced until class und is declared\n") + ); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/jdk/jshell/ToolBasicTest.java --- a/langtools/test/jdk/jshell/ToolBasicTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/jdk/jshell/ToolBasicTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -23,14 +23,16 @@ /* * @test - * @bug 8143037 8142447 8144095 8140265 + * @bug 8143037 8142447 8144095 8140265 8144906 + * @requires os.family != "solaris" * @summary Tests for Basic tests for REPL tool * @library /tools/lib * @ignore 8139873 * @build KullaTesting TestingInputStream ToolBox Compiler - * @run testng ToolBasicTest + * @run testng/timeout=600 ToolBasicTest */ +import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; @@ -460,8 +462,7 @@ Path unknown = compiler.getPath("UNKNOWN.jar"); test(true, new String[]{unknown.toString()}, "| File '" + unknown - + "' is not found: " + unknown - + " (No such file or directory)\n"); + + "' is not found: " + unresolvableMessage(unknown) + "\n"); } public void testReset() { @@ -514,8 +515,7 @@ test( (a) -> assertCommand(a, s + " " + unknown, "| File '" + unknown - + "' is not found: " + unknown - + " (No such file or directory)\n") + + "' is not found: " + unresolvableMessage(unknown) + "\n") ); } } @@ -874,6 +874,15 @@ ); } + private String unresolvableMessage(Path p) { + try { + new FileInputStream(p.toFile()); + throw new AssertionError("Expected exception did not occur."); + } catch (IOException ex) { + return ex.getMessage(); + } + } + public void testCommandPrefix() { test(a -> assertCommandCheckOutput(a, "/s", assertStartsWith("| Command: /s is ambiguous: /seteditor, /save, /setstart")), diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/jdk/jshell/ToolReloadTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/jdk/jshell/ToolReloadTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8081845 + * @summary Tests for /reload in JShell tool + * @library /tools/lib + * @build KullaTesting TestingInputStream ToolBox Compiler + * @run testng ToolReloadTest + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.function.Function; + +import org.testng.annotations.Test; + + +@Test +public class ToolReloadTest extends ReplToolTesting { + + public void testReloadSnippets() { + test( + (a) -> assertVariable(a, "int", "x", "5", "5"), + (a) -> assertMethod(a, "int m(int z) { return z * z; }", + "(int)int", "m"), + (a) -> evaluateExpression(a, "int", "m(x)", "25"), + (a) -> assertCommand(a, "/reload", + "| Restarting and restoring state.\n" + + "-: int x = 5;\n" + + "-: int m(int z) { return z * z; }\n" + + "-: m(x)\n"), + (a) -> evaluateExpression(a, "int", "m(x)", "25"), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) + ); + } + + public void testReloadClasspath() { + Function prog = (s) -> String.format( + "package pkg; public class A { public String toString() { return \"%s\"; } }\n", s); + Compiler compiler = new Compiler(); + Path outDir = Paths.get("testClasspathDirectory"); + compiler.compile(outDir, prog.apply("A")); + Path classpath = compiler.getPath(outDir); + test( + (a) -> assertCommand(a, "/classpath " + classpath, + String.format("| Path %s added to classpath\n", classpath)), + (a) -> assertMethod(a, "String foo() { return (new pkg.A()).toString(); }", + "()String", "foo"), + (a) -> assertVariable(a, "String", "v", "foo()", "\"A\""), + (a) -> { + if (!a) compiler.compile(outDir, prog.apply("Aprime")); + assertCommand(a, "/reload", + "| Restarting and restoring state.\n" + + "-: /classpath " + classpath + "\n" + + "-: String foo() { return (new pkg.A()).toString(); }\n" + + "-: String v = foo();\n"); + }, + (a) -> assertCommand(a, "v", "| Variable v of type String has value \"Aprime\"\n"), + (a) -> evaluateExpression(a, "String", "foo()", "\"Aprime\""), + (a) -> evaluateExpression(a, "pkg.A", "new pkg.A();", "\"Aprime\"") + ); + } + + public void testReloadDrop() { + test(false, new String[]{"-nostartup"}, + a -> assertVariable(a, "int", "a"), + a -> dropVariable(a, "/dr 1", "int a = 0"), + a -> assertMethod(a, "int b() { return 0; }", "()I", "b"), + a -> dropMethod(a, "/drop b", "b ()I"), + a -> assertClass(a, "class A {}", "class", "A"), + a -> dropClass(a, "/dr A", "class A"), + a -> assertCommand(a, "/reload", + "| Restarting and restoring state.\n" + + "-: int a;\n" + + "-: /drop 1\n" + + "-: int b() { return 0; }\n" + + "-: /drop b\n" + + "-: class A {}\n" + + "-: /drop A\n"), + a -> assertCommandCheckOutput(a, "/vars", assertVariables()), + a -> assertCommandCheckOutput(a, "/methods", assertMethods()), + a -> assertCommandCheckOutput(a, "/classes", assertClasses()), + a -> assertCommandCheckOutput(a, "/imports", assertImports()) + ); + } + + public void testReloadRepeat() { + test(false, new String[]{"-nostartup"}, + (a) -> assertVariable(a, "int", "c", "7", "7"), + (a) -> assertCommand(a, "++c", null), + (a) -> assertCommand(a, "/!", null), + (a) -> assertCommand(a, "/2", null), + (a) -> assertCommand(a, "/-1", null), + (a) -> assertCommand(a, "/reload", + "| Restarting and restoring state.\n" + + "-: int c = 7;\n" + + "-: ++c\n" + + "-: ++c\n" + + "-: ++c\n" + + "-: ++c\n" + ), + (a) -> assertCommand(a, "c", "| Variable c of type int has value 11\n"), + (a) -> assertCommand(a, "$4", "| Variable $4 of type int has value 10\n") + ); + } + + public void testReloadIgnore() { + test(false, new String[]{"-nostartup"}, + (a) -> assertCommand(a, "(-)", null), + (a) -> assertCommand(a, "/list", null), + (a) -> assertCommand(a, "/history", null), + (a) -> assertCommand(a, "/help", null), + (a) -> assertCommand(a, "/vars", null), + (a) -> assertCommand(a, "/save abcd", null), + (a) -> assertCommand(a, "/reload", + "| Restarting and restoring state.\n") + ); + } + + public void testReloadResetRestore() { + test( + (a) -> assertVariable(a, "int", "x", "5", "5"), + (a) -> assertMethod(a, "int m(int z) { return z * z; }", + "(int)int", "m"), + (a) -> evaluateExpression(a, "int", "m(x)", "25"), + (a) -> assertCommand(a, "/reset", "| Resetting state.\n"), + (a) -> assertCommand(a, "/reload restore", + "| Restarting and restoring from previous state.\n" + + "-: int x = 5;\n" + + "-: int m(int z) { return z * z; }\n" + + "-: m(x)\n"), + (a) -> evaluateExpression(a, "int", "m(x)", "25"), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) + ); + } + + public void testReloadCrashRestore() { + test( + (a) -> assertVariable(a, "int", "x", "5", "5"), + (a) -> assertMethod(a, "int m(int z) { return z * z; }", + "(int)int", "m"), + (a) -> evaluateExpression(a, "int", "m(x)", "25"), + (a) -> assertCommand(a, "System.exit(1);", + "| State engine terminated.\n" + + "| Restore definitions with: /reload restore\n"), + (a) -> assertCommand(a, "/reload restore", + "| Restarting and restoring from previous state.\n" + + "-: int x = 5;\n" + + "-: int m(int z) { return z * z; }\n" + + "-: m(x)\n"), + (a) -> evaluateExpression(a, "int", "m(x)", "25"), + (a) -> assertCommandCheckOutput(a, "/vars", assertVariables()), + (a) -> assertCommandCheckOutput(a, "/methods", assertMethods()) + ); + } + + public void testReloadExitRestore() { + test(false, new String[]{"-nostartup"}, + (a) -> assertVariable(a, "int", "x", "5", "5"), + (a) -> assertMethod(a, "int m(int z) { return z * z; }", + "(int)int", "m"), + (a) -> evaluateExpression(a, "int", "m(x)", "25") + ); + test(false, new String[]{"-nostartup"}, + (a) -> assertCommand(a, "/reload restore", + "| Restarting and restoring from previous state.\n" + + "-: int x = 5;\n" + + "-: int m(int z) { return z * z; }\n" + + "-: m(x)\n"), + (a) -> evaluateExpression(a, "int", "m(x)", "25") + ); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/BadHexConstant.java --- a/langtools/test/tools/javac/BadHexConstant.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/javac/BadHexConstant.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 4049982 + * @bug 4049982 8056897 * @summary Compiler permitted invalid hex literal. * @author turnidge * diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/BadHexConstant.out --- a/langtools/test/tools/javac/BadHexConstant.out Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/javac/BadHexConstant.out Wed Jul 05 21:13:10 2017 +0200 @@ -1,3 +1,2 @@ BadHexConstant.java:12:14: compiler.err.invalid.hex.number -BadHexConstant.java:12:17: compiler.err.expected: token.identifier -2 errors +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/api/T6430241.java --- a/langtools/test/tools/javac/api/T6430241.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 6430241 - * @summary Hard to disable symbol file feature through API - * @library /tools/lib - * @modules jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.file - * jdk.compiler/com.sun.tools.javac.main - * jdk.compiler/com.sun.tools.javac.util - * @build ToolBox - * @run main T6430241 - */ - -import java.io.*; -import java.util.*; - -import javax.tools.*; - -import com.sun.source.util.JavacTask; -import com.sun.tools.javac.api.JavacTool; -import com.sun.tools.javac.file.JavacFileManager; -import com.sun.tools.javac.util.Context; - -public class T6430241 { - public static void main(String... args) throws Exception { - new T6430241().run(); - } - - void run() throws Exception { - setup(); - testCommandLine(); - testSimpleAPI(); - testTaskAPI(); - - if (errors > 0) - throw new Exception(errors + " errors found"); - } - - void setup() throws Exception { - classesDir = new File("classes"); - classesDir.mkdirs(); - - emptyDir = new File("empty"); - emptyDir.mkdirs(); - - bootClassPath = createJar().getPath(); - - File srcDir = new File("src"); - String test = "import sun.misc.Unsafe; class Test { }"; - testFile = writeFile(srcDir, "Test.java", test); - } - - //----- tests for command line invocation - - void testCommandLine() throws Exception { - testCommandLine(true); - testCommandLine(false, "-Xbootclasspath/p:" + emptyDir); - testCommandLine(false, "-Xbootclasspath:" + bootClassPath); - testCommandLine(false, "-Xbootclasspath/a:" + emptyDir); - testCommandLine(false, "-XDignore.symbol.file"); - System.err.println(); - } - - void testCommandLine(boolean expectWarnings, String... opts) throws Exception { - System.err.println("test command line: " + Arrays.asList(opts)); - - String[] args = initArgs(opts); - - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - int rc = com.sun.tools.javac.Main.compile(args, pw); - String out = showOutput(sw.toString()); - - checkCompilationOK(rc); - checkOutput(out, expectWarnings); - } - - //----- tests for simple API invocation - - void testSimpleAPI() { - testSimpleAPI(true); - testSimpleAPI(false, "-Xbootclasspath/p:" + emptyDir); - testSimpleAPI(false, "-Xbootclasspath:" + bootClassPath); - testSimpleAPI(false, "-Xbootclasspath/a:" + emptyDir); - testSimpleAPI(false, "-XDignore.symbol.file"); - System.err.println(); - } - - void testSimpleAPI(boolean expectWarnings, String... opts) { - System.err.println("test simple API: " + Arrays.asList(opts)); - - String[] args = initArgs(opts); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - - JavacTool tool = JavacTool.create(); - int rc = tool.run(null, null, ps, args); - - String out = showOutput(baos.toString()); - - checkCompilationOK(rc); - checkOutput(out, expectWarnings); - } - - //----- tests for CompilationTask API invocation - - void testTaskAPI() throws Exception { - List bcp = new ArrayList(); - for (String f: bootClassPath.split(File.pathSeparator)) { - if (!f.isEmpty()) - bcp.add(new File(f)); - } - - testTaskAPI(true, null); - testTaskAPI(false, bcp); - System.err.println(); - } - - void testTaskAPI(boolean expectWarnings, Iterable pcp) throws Exception { - System.err.println("test task API: " + pcp); - - JavacTool tool = JavacTool.create(); - try (StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null)) { - - if (pcp != null) - fm.setLocation(StandardLocation.PLATFORM_CLASS_PATH, pcp); - - Iterable files = fm.getJavaFileObjects(testFile); - - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - JavacTask task = tool.getTask(pw, fm, null, null, null, files); - boolean ok = task.call(); - String out = showOutput(sw.toString()); - - checkCompilationOK(ok); - checkOutput(out, expectWarnings); - } - } - - //----- utility methods - - File createJar() throws IOException { - File f = new File("test.jar"); - try (JavaFileManager fm = new JavacFileManager(new Context(), false, null)) { - ToolBox tb = new ToolBox(); - tb.new JarTask(f.getPath()) - .files(fm, StandardLocation.PLATFORM_CLASS_PATH, "java.lang.*", "sun.misc.*") - .run(); - } - return f; - } - - /** - * Create a file with given content. - */ - File writeFile(File dir, String path, String content) throws IOException { - File f = new File(dir, path); - f.getParentFile().mkdirs(); - FileWriter out = new FileWriter(f); - try { - out.write(content); - } finally { - out.close(); - } - return f; - } - - /** - * Initialize args for compilation with given opts. - * @return opts -d classesDir testFile - */ - String[] initArgs(String[] opts) { - List args = new ArrayList(); - args.addAll(Arrays.asList(opts)); - args.add("-d"); - args.add(classesDir.getPath()); - args.add(testFile.getPath()); - return args.toArray(new String[args.size()]); - } - - /** - * Show output from compilation if non empty. - */ - String showOutput(String out) { - if (!out.isEmpty()) - System.err.println(out); - return out; - } - - /** - * Verify compilation succeeded. - */ - void checkCompilationOK(boolean ok) { - if (!ok) - error("compilation failed"); - } - - /** - * Verify compilation succeeded. - */ - void checkCompilationOK(int rc) { - if (rc != 0) - error("compilation failed, rc: " + rc); - } - - /** - * Check whether output contains warnings if and only if warnings - * are expected. - */ - void checkOutput(String out, boolean expectWarnings) { - boolean foundWarnings = out.contains("warning"); - if (foundWarnings) { - if (!expectWarnings) - error("unexpected warnings found"); - } else { - if (expectWarnings) - error("expected warnings not found"); - } - } - - /** - * Report an error. - */ - void error(String msg) { - System.err.println("error: " + msg); - errors++; - } - - String bootClassPath; - File classesDir; - File emptyDir; - File testFile; - int errors; -} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/diags/examples/IdentifierExpected.java --- a/langtools/test/tools/javac/diags/examples/IdentifierExpected.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/javac/diags/examples/IdentifierExpected.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,9 @@ // key: compiler.misc.token.identifier // key: compiler.err.expected -// key: compiler.err.invalid.binary.number -// key: compiler.misc.count.error.plural +// key: compiler.misc.count.error // key: compiler.err.error // run: backdoor -class IdentifierExpected { - long bl = 0BL; +class { } diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/file/BootClassPathPrepend.java --- a/langtools/test/tools/javac/file/BootClassPathPrepend.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 8067445 - * @summary Verify that file.Locations analyze sun.boot.class.path for BCP prepends/appends - * @library /tools/lib - * @modules jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.file - * jdk.compiler/com.sun.tools.javac.main - */ - -import java.io.IOException; -import java.util.EnumSet; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; -import javax.tools.StandardLocation; -import javax.tools.ToolProvider; - -public class BootClassPathPrepend { - public static void main(String... args) throws IOException { - if (args.length == 0) { - new BootClassPathPrepend().reRun(); - } else { - new BootClassPathPrepend().run(); - } - } - - void reRun() { - String testClasses = System.getProperty("test.classes"); - ToolBox tb = new ToolBox(); - tb.new JavaTask().vmOptions("-Xbootclasspath/p:" + testClasses) - .classArgs("real-run") - .className("BootClassPathPrepend") - .run() - .writeAll(); - } - - EnumSet classKind = EnumSet.of(JavaFileObject.Kind.CLASS); - - void run() throws IOException { - JavaCompiler toolProvider = ToolProvider.getSystemJavaCompiler(); - try (JavaFileManager fm = toolProvider.getStandardFileManager(null, null, null)) { - Iterable files = - fm.list(StandardLocation.PLATFORM_CLASS_PATH, "", classKind, false); - for (JavaFileObject fo : files) { - if (fo.isNameCompatible("BootClassPathPrepend", JavaFileObject.Kind.CLASS)) { - System.err.println("Found BootClassPathPrepend on bootclasspath"); - return ;//found - } - } - - throw new AssertionError("Cannot find class that was prepended on BCP"); - } - } -} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific15.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific15.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143852 + * @summary Rename functional interface method type parameters during most specific test + * @compile MostSpecific15.java + */ +class MostSpecific15 { + interface F1 { Object apply(X arg); } + interface F2 { String apply(Y arg); } + + static void m1(F1 f) {} + static void m1(F2 f) {} + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific15::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific16.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific16.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Rename functional interface method type parameters during most specific test + * @compile/fail/ref=MostSpecific16.out -XDrawDiagnostics MostSpecific16.java + */ +class MostSpecific16 { + interface F1 { Object apply(Object arg); } + interface F2 { String apply(Object arg); } + + static void m1(F1 f) {} + static void m1(F2 f) {} + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific16::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific16.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific16.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific16.java:17:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific16.F1), MostSpecific16, kindname.method, m1(MostSpecific16.F2), MostSpecific16 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific17.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific17.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143852 + * @summary Rename functional interface method type parameters during most specific test + * @compile MostSpecific17.java + */ +class MostSpecific17 { + + interface A {} + interface B extends A {} + + interface F1 { A apply(Object arg); } + interface F2 { B apply(Object arg); } + + static void m1(F1 f) {} + static void m1(F2 f) {} + + static B foo(Object in) { return null; } + + void test() { + m1(MostSpecific17::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific18.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific18.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143852 + * @summary Test that generic function interface method bounds are the same + * @compile MostSpecific18.java + */ +class MostSpecific18 { + interface F1 { Object apply(X arg); } + interface F2 { String apply(Y arg); } + + static void m1(F1 f) {} + static void m1(F2 f) {} + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific18::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific19.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific19.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Test that generic function interface method bounds are the same + * @compile/fail/ref=MostSpecific19.out -XDrawDiagnostics MostSpecific19.java + */ +class MostSpecific19 { + interface F1 { Object apply(X arg); } + interface F2 { String apply(Y arg); } + + static void m1(F1 f) {} + static void m1(F2 f) {} + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific19::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific19.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific19.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific19.java:17:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific19.F1), MostSpecific19, kindname.method, m1(MostSpecific19.F2), MostSpecific19 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific20.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific20.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143852 + * @summary Test that generic function interface method bounds are the same + * @compile MostSpecific20.java + */ +class MostSpecific20 { + interface F1 { > Object apply(X arg); } + interface F2 { > String apply(Y arg); } + + static void m1(F1 f) {} + static void m1(F2 f) {} + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific20::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific21.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific21.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Most specific inference constraints derived from both functional interface method parameters and tparam bounds + * @compile/fail/ref=MostSpecific21.out -XDrawDiagnostics MostSpecific21.java + */ +class MostSpecific21 { + interface F1 { Object apply(T arg); } + interface F2 { String apply(Integer arg); } + + static T m1(F1 f) { return null; } + static Object m1(F2 f) { return null; } + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific21::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific21.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific21.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific21.java:17:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific21.F1), MostSpecific21, kindname.method, m1(MostSpecific21.F2), MostSpecific21 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific22.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific22.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143852 + * @summary Most specific inference constraints derived from both functional interface method parameters and tparam bounds + * @compile MostSpecific22.java + */ +class MostSpecific22 { + interface F1 { Object apply(T arg); } + interface F2 { String apply(Number arg); } + + static T m1(F1 f) { return null; } + static Object m1(F2 f) { return null; } + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific22::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific23.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific23.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Most specific failure if ivar can be bounded by functional interface method tparam + * @compile/fail/ref=MostSpecific23.out -XDrawDiagnostics MostSpecific23.java + */ +class MostSpecific23 { + interface F1 { Object apply(Integer arg); } + interface F2 { > String apply(Integer arg); } + + static T m1(F1 f) { return null; } + static Object m1(F2 f) { return null; } + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific23::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific23.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific23.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific23.java:17:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific23.F1), MostSpecific23, kindname.method, m1(MostSpecific23.F2), MostSpecific23 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific24.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific24.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Most specific failure if ivar can be bounded by functional interface method tparam + * @compile/fail/ref=MostSpecific24.out -XDrawDiagnostics MostSpecific24.java + */ +class MostSpecific24 { + interface F1 { Object apply(Class arg); } + interface F2 { String apply(Class arg); } + + static T m1(F1 f) { return null; } + static Object m1(F2 f) { return null; } + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific24::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific24.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific24.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific24.java:17:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific24.F1), MostSpecific24, kindname.method, m1(MostSpecific24.F2), MostSpecific24 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific25.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific25.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Most specific failure if ivar can be bounded by functional interface method tparam + * @compile/fail/ref=MostSpecific25.out -XDrawDiagnostics MostSpecific25.java + */ +class MostSpecific25 { + interface F1 { T apply(Integer arg); } + interface F2 { Class apply(Integer arg); } + + static T m1(F1 f) { return null; } + static Object m1(F2 f) { return null; } + + static Class foo(Object in) { return Object.class; } + + void test() { + m1(MostSpecific25::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific25.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific25.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific25.java:17:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific25.F1), MostSpecific25, kindname.method, m1(MostSpecific25.F2), MostSpecific25 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific26.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific26.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,20 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Most specific inference constraints derived from intersection bound + * @compile/fail/ref=MostSpecific26.out -XDrawDiagnostics MostSpecific26.java + */ +class MostSpecific26 { + interface F1 { & Runnable> Object apply(T arg); } + interface F2 { & Runnable> String apply(Integer arg); } + + static T m1(F1 f) { return null; } + static Object m1(F2 f) { return null; } + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific26::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific26.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific26.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific26.java:17:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific26.F1), MostSpecific26, kindname.method, m1(MostSpecific26.F2), MostSpecific26 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific27.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific27.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8143852 + * @summary Most specific inference constraints derived from intersection bound + * @compile MostSpecific27.java + */ +class MostSpecific27 { + interface F1 { & Runnable> Object apply(T arg); } + interface F2 { & Runnable> String apply(Number arg); } + + static T m1(F1 f) { return null; } + static Object m1(F2 f) { return null; } + + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific27::foo); + } + +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific28.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific28.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,21 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8143852 + * @summary Test that functional interface method parameter types are equal, even for an explicit lambda + * @compile/fail/ref=MostSpecific28.out -XDrawDiagnostics MostSpecific28.java + */ +class MostSpecific28 { + + interface Pred { boolean test(T arg); } + interface Fun { R apply(T arg); } + + static void m1(Pred f) {} + static void m1(Fun f) {} + + static String foo(Object in) { return "a"; } + + void test() { + m1((Number n) -> true); + } + +} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lambda/MostSpecific28.out --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lambda/MostSpecific28.out Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,2 @@ +MostSpecific28.java:18:9: compiler.err.ref.ambiguous: m1, kindname.method, m1(MostSpecific28.Pred), MostSpecific28, kindname.method, m1(MostSpecific28.Fun), MostSpecific28 +1 error diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/lexer/JavaLexerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/lexer/JavaLexerTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8056897 + * @summary Proper lexing of integer literals. + */ + +import java.io.IOException; +import java.net.URI; +import java.util.Objects; + +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; + +import com.sun.tools.javac.parser.JavaTokenizer; +import com.sun.tools.javac.parser.ScannerFactory; +import com.sun.tools.javac.parser.Tokens.Token; +import com.sun.tools.javac.parser.Tokens.TokenKind; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Log; + +public class JavaLexerTest { + public static void main(String... args) throws Exception { + new JavaLexerTest().run(); + } + + void run() throws Exception { + Context ctx = new Context(); + Log log = Log.instance(ctx); + String input = "0bL 0b20L 0xL "; + log.useSource(new SimpleJavaFileObject(new URI("mem://Test.java"), JavaFileObject.Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return input; + } + }); + char[] inputArr = input.toCharArray(); + JavaTokenizer tokenizer = new JavaTokenizer(ScannerFactory.instance(ctx), inputArr, inputArr.length) { + }; + + assertKind(input, tokenizer, TokenKind.LONGLITERAL, "0bL"); + assertKind(input, tokenizer, TokenKind.LONGLITERAL, "0b20L"); + assertKind(input, tokenizer, TokenKind.LONGLITERAL, "0xL"); + } + + void assertKind(String input, JavaTokenizer tokenizer, TokenKind kind, String expectedText) { + Token token = tokenizer.readToken(); + + if (token.kind != kind) { + throw new AssertionError("Unexpected token kind: " + token.kind); + } + + String actualText = input.substring(token.pos, token.endPos); + + if (!Objects.equals(actualText, expectedText)) { + throw new AssertionError("Unexpected token text: " + actualText); + } + } +} \ No newline at end of file diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/literals/T6891079.java --- a/langtools/test/tools/javac/literals/T6891079.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/javac/literals/T6891079.java Wed Jul 05 21:13:10 2017 +0200 @@ -1,5 +1,5 @@ /* @test /nodynamiccopyright/ - * @bug 6891079 + * @bug 6891079 8056897 * @summary Compiler allows invalid binary literals 0b and oBL * @compile/fail/ref=T6891079.out -XDrawDiagnostics T6891079.java */ diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/javac/literals/T6891079.out --- a/langtools/test/tools/javac/literals/T6891079.out Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/javac/literals/T6891079.out Wed Jul 05 21:13:10 2017 +0200 @@ -1,7 +1,5 @@ T6891079.java:8:14: compiler.err.invalid.binary.number T6891079.java:9:15: compiler.err.invalid.binary.number -T6891079.java:9:18: compiler.err.expected: token.identifier T6891079.java:10:14: compiler.err.invalid.hex.number T6891079.java:11:15: compiler.err.invalid.hex.number -T6891079.java:11:18: compiler.err.expected: token.identifier -6 errors +4 errors diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/CompileExcludingDependency.java --- a/langtools/test/tools/sjavac/CompileExcludingDependency.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/sjavac/CompileExcludingDependency.java Wed Jul 05 21:13:10 2017 +0200 @@ -55,9 +55,9 @@ tb.writeFile(GENSRC.resolve("beta/B.java"), "package beta; public class B { }"); - compile("-x", "beta", + compile("-x", "beta/*", "-src", GENSRC.toString(), - "-x", "alfa/omega", + "-x", "alfa/omega/*", "-sourcepath", GENSRC.toString(), "-d", BIN.toString(), "--state-dir=" + BIN, diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/CompileWithAtFile.java --- a/langtools/test/tools/sjavac/CompileWithAtFile.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/sjavac/CompileWithAtFile.java Wed Jul 05 21:13:10 2017 +0200 @@ -47,8 +47,8 @@ void test() throws Exception { tb.writeFile(GENSRC.resolve("list.txt"), - "-if */alfa/omega/A.java\n" + - "-if */beta/B.java\n" + + "-i alfa/omega/A.java\n" + + "-i beta/B.java\n" + GENSRC + "\n" + "-d " + BIN + "\n" + "--state-dir=" + BIN + "\n"); diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/CompileWithInvisibleSources.java --- a/langtools/test/tools/sjavac/CompileWithInvisibleSources.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/sjavac/CompileWithInvisibleSources.java Wed Jul 05 21:13:10 2017 +0200 @@ -64,7 +64,7 @@ "package beta; public class B { }"); compile(GENSRC.toString(), - "-x", "beta", + "-x", "beta/*", "-sourcepath", GENSRC2.toString(), "-sourcepath", GENSRC3.toString(), "-d", BIN.toString(), diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/CompileWithOverrideSources.java --- a/langtools/test/tools/sjavac/CompileWithOverrideSources.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/sjavac/CompileWithOverrideSources.java Wed Jul 05 21:13:10 2017 +0200 @@ -62,7 +62,7 @@ tb.writeFile(GENSRC2.resolve("beta/B.java"), "package beta; public class B { }"); - compile("-x", "beta", + compile("-x", "beta/*", GENSRC.toString(), GENSRC2.toString(), "-d", BIN.toString(), diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/ExclPattern.java --- a/langtools/test/tools/sjavac/ExclPattern.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8037085 - * @summary Ensures that sjavac can handle various exclusion patterns. - * - * @modules jdk.compiler/com.sun.tools.sjavac - * @build Wrapper - * @run main Wrapper ExclPattern - */ - -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -public class ExclPattern { - - public static void main(String[] ignore) throws IOException { - - String toBeExcluded = "pkg/excl-dir/excluded.txt"; - String toBeIncluded = "pkg/incl-dir/included.txt"; - - // Set up source directory with directory to be excluded - populate(Paths.get("srcdir"), - "pkg/SomeClass.java", - "package pkg; public class SomeClass { }", - - toBeExcluded, - "This file should not end up in the dest directory.", - - toBeIncluded, - "This file should end up in the dest directory."); - - String[] args = { - "-x", "pkg/excl-dir/*", - "-src", "srcdir", - "-d", "dest", - "--state-dir=dest", - "-j", "1", - "-copy", ".txt", - "--server:portfile=testserver,background=false", - "--log=debug" - }; - - int rc = com.sun.tools.sjavac.Main.go(args); - if (rc != 0) throw new RuntimeException("Error during compile!"); - - if (!Files.exists(Paths.get("dest/" + toBeIncluded))) - throw new AssertionError("File missing: " + toBeIncluded); - - if (Files.exists(Paths.get("dest/" + toBeExcluded))) - throw new AssertionError("File present: " + toBeExcluded); - } - - static void populate(Path root, String... args) throws IOException { - if (!Files.exists(root)) - Files.createDirectory(root); - for (int i = 0; i < args.length; i += 2) { - String filename = args[i]; - String content = args[i+1]; - Path p = root.resolve(filename); - Files.createDirectories(p.getParent()); - try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(p, - Charset.defaultCharset()))) { - out.println(content); - } - } - } -} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/HiddenFiles.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/sjavac/HiddenFiles.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8144226 + * @summary Ensures that excluded files are inaccessible (even for implicit + * compilation) + * + * @modules jdk.compiler/com.sun.tools.sjavac + * @library /tools/lib + * @build Wrapper ToolBox + * @run main Wrapper HiddenFiles + */ + +import com.sun.tools.javac.util.Assert; +import com.sun.tools.sjavac.server.Sjavac; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class HiddenFiles extends SjavacBase { + + public static void main(String[] ignore) throws Exception { + Path BIN = Paths.get("bin"); + Path STATE_DIR = Paths.get("state-dir"); + Path SRC = Paths.get("src"); + + Files.createDirectories(BIN); + Files.createDirectories(STATE_DIR); + + toolbox.writeJavaFiles(SRC, "package pkg; class A { B b; }"); + toolbox.writeJavaFiles(SRC, "package pkg; class B { }"); + + // This compilation should fail (return RC_FATAL) since A.java refers to B.java and B.java + // is excluded. + int rc = compile("-x", "pkg/B.java", SRC.toString(), + "--server:portfile=testportfile,background=false", + "-d", BIN.toString(), + "--state-dir=" + STATE_DIR); + + Assert.check(rc == Sjavac.RC_FATAL, "Compilation succeeded unexpectedly."); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/IncludeExcludePatterns.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/sjavac/IncludeExcludePatterns.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8037085 + * @summary Ensures that sjavac can handle various exclusion patterns. + * + * @modules jdk.compiler/com.sun.tools.sjavac + * @library /tools/lib + * @build Wrapper ToolBox + * @run main Wrapper IncludeExcludePatterns + */ + +import com.sun.tools.javac.util.Assert; +import com.sun.tools.sjavac.server.Sjavac; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class IncludeExcludePatterns extends SjavacBase { + + final Path SRC = Paths.get("src"); + final Path BIN = Paths.get("bin"); + final Path STATE_DIR = Paths.get("state-dir"); + + // An arbitrarily but sufficiently complicated source tree. + final Path A = Paths.get("pkga/A.java"); + final Path X1 = Paths.get("pkga/subpkg/Xx.java"); + final Path Y = Paths.get("pkga/subpkg/subsubpkg/Y.java"); + final Path B = Paths.get("pkgb/B.java"); + final Path C = Paths.get("pkgc/C.java"); + final Path X2 = Paths.get("pkgc/Xx.java"); + + final Path[] ALL_PATHS = {A, X1, Y, B, C, X2}; + + public static void main(String[] ignore) throws Exception { + new IncludeExcludePatterns().runTest(); + } + + public void runTest() throws IOException, ReflectiveOperationException { + Files.createDirectories(BIN); + Files.createDirectories(STATE_DIR); + for (Path p : ALL_PATHS) { + writeDummyClass(p); + } + + // Single file + testPattern("pkga/A.java", A); + + // Leading wild cards + testPattern("*/A.java", A); + testPattern("**/Xx.java", X1, X2); + testPattern("**x.java", X1, X2); + + // Wild card in middle of path + testPattern("pkga/*/Xx.java", X1); + testPattern("pkga/**/Y.java", Y); + + // Trailing wild cards + testPattern("pkga/*", A); + testPattern("pkga/**", A, X1, Y); + + // Multiple wildcards + testPattern("pkga/*/*/Y.java", Y); + testPattern("**/*/**", X1, Y); + + } + + // Given "src/pkg/subpkg/A.java" this method returns "A" + String classNameOf(Path javaFile) { + return javaFile.getFileName() + .toString() + .replace(".java", ""); + } + + // Puts an empty (dummy) class definition in the given path. + void writeDummyClass(Path javaFile) throws IOException { + String pkg = javaFile.getParent().toString().replace(File.separatorChar, '.'); + String cls = javaFile.getFileName().toString().replace(".java", ""); + toolbox.writeFile(SRC.resolve(javaFile), "package " + pkg + "; class " + cls + " {}"); + } + + void testPattern(String filterArgs, Path... sourcesExpectedToBeVisible) + throws ReflectiveOperationException, IOException { + testFilter("-i " + filterArgs, Arrays.asList(sourcesExpectedToBeVisible)); + + Set complement = new HashSet<>(Arrays.asList(ALL_PATHS)); + complement.removeAll(Arrays.asList(sourcesExpectedToBeVisible)); + testFilter("-x " + filterArgs, complement); + } + + void testFilter(String filterArgs, Collection sourcesExpectedToBeVisible) + throws IOException, ReflectiveOperationException { + System.out.println("Testing filter: " + filterArgs); + toolbox.cleanDirectory(BIN); + toolbox.cleanDirectory(STATE_DIR); + String args = filterArgs + " " + SRC + + " --server:portfile=testportfile,background=false" + + " -d " + BIN + + " --state-dir=" + STATE_DIR; + int rc = compile((Object[]) args.split(" ")); + + // Compilation should always pass in these tests + Assert.check(rc == Sjavac.RC_OK, "Compilation failed unexpectedly."); + + // The resulting .class files should correspond to the visible source files + Set result = allFilesInDir(BIN); + Set expected = correspondingClassFiles(sourcesExpectedToBeVisible); + if (!result.equals(expected)) { + System.out.println("Result:"); + printPaths(result); + System.out.println("Expected:"); + printPaths(expected); + Assert.error("Test case failed: " + filterArgs); + } + } + + void printPaths(Collection paths) { + paths.stream() + .sorted() + .forEachOrdered(p -> System.out.println(" " + p)); + } + + // Given "pkg/A.java, pkg/B.java" this method returns "bin/pkg/A.class, bin/pkg/B.class" + Set correspondingClassFiles(Collection javaFiles) { + return javaFiles.stream() + .map(javaFile -> javaFile.resolveSibling(classNameOf(javaFile) + ".class")) + .map(BIN::resolve) + .collect(Collectors.toSet()); + } + + Set allFilesInDir(Path p) throws IOException { + try (Stream files = Files.walk(p).filter(Files::isRegularFile)) { + return files.collect(Collectors.toSet()); + } + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/OptionDecoding.java --- a/langtools/test/tools/sjavac/OptionDecoding.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/sjavac/OptionDecoding.java Wed Jul 05 21:13:10 2017 +0200 @@ -61,7 +61,6 @@ public static void main(String[] args) throws IOException { testPaths(); testDupPaths(); - testSourceLocations(); testSimpleOptions(); testServerConf(); testSearchPaths(); @@ -110,78 +109,6 @@ } } - // Test source locations and -x, -i, -xf, -if filters - static void testSourceLocations() throws IOException { - Path a1 = Paths.get("root/pkg1/ClassA1.java"); - Path a2 = Paths.get("root/pkg1/ClassA2.java"); - Path b1 = Paths.get("root/pkg1/pkg2/ClassB1.java"); - Path b2 = Paths.get("root/pkg1/pkg2/ClassB2.java"); - Path c1 = Paths.get("root/pkg3/ClassC1.java"); - Path c2 = Paths.get("root/pkg3/ClassC2.java"); - - for (Path p : Arrays.asList(a1, a2, b1, b2, c1, c2)) { - Files.createDirectories(p.getParent()); - Files.createFile(p); - } - - // Test -if - { - Options options = Options.parseArgs("-if", "root/pkg1/ClassA1.java", "root"); - - Map foundFiles = new HashMap<>(); - SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles, - new HashMap(), new Module("", ""), false, true); - - checkFilesFound(foundFiles.keySet(), a1); - } - - // Test -i - System.out.println("--------------------------- CHECKING -i ----------------"); - { - Options options = Options.parseArgs("-i", "pkg1/*", "root"); - - Map foundFiles = new HashMap<>(); - SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles, - new HashMap(), new Module("", ""), false, true); - - checkFilesFound(foundFiles.keySet(), a1, a2, b1, b2); - } - System.out.println("--------------------------------------------------------"); - - // Test -xf - { - Options options = Options.parseArgs("-xf", "root/pkg1/ClassA1.java", "root"); - - Map foundFiles = new HashMap<>(); - SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles, - new HashMap(), new Module("", ""), false, true); - - checkFilesFound(foundFiles.keySet(), a2, b1, b2, c1, c2); - } - - // Test -x - { - Options options = Options.parseArgs("-i", "pkg1/*", "root"); - - Map foundFiles = new HashMap<>(); - SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles, - new HashMap(), new Module("", ""), false, true); - - checkFilesFound(foundFiles.keySet(), a1, a2, b1, b2); - } - - // Test -x and -i - { - Options options = Options.parseArgs("-i", "pkg1/*", "-x", "pkg1/pkg2/*", "root"); - - Map foundFiles = new HashMap<>(); - SjavacImpl.findSourceFiles(options.getSources(), Collections.singleton(".java"), foundFiles, - new HashMap(), new Module("", ""), false, true); - - checkFilesFound(foundFiles.keySet(), a1, a2); - } - } - // Test basic options static void testSimpleOptions() { Options options = Options.parseArgs("-j", "17", "--log=debug"); @@ -216,8 +143,8 @@ List i, x, iF, xF; i = x = iF = xF = new ArrayList<>(); - SourceLocation dir1 = new SourceLocation(Paths.get("dir1"), i, x, iF, xF); - SourceLocation dir2 = new SourceLocation(Paths.get("dir2"), i, x, iF, xF); + SourceLocation dir1 = new SourceLocation(Paths.get("dir1"), i, x); + SourceLocation dir2 = new SourceLocation(Paths.get("dir2"), i, x); String dir1_PS_dir2 = "dir1" + File.pathSeparator + "dir2"; Options options = Options.parseArgs("-sourcepath", dir1_PS_dir2); diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/Serialization.java --- a/langtools/test/tools/sjavac/Serialization.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/sjavac/Serialization.java Wed Jul 05 21:13:10 2017 +0200 @@ -58,8 +58,6 @@ Option.D.arg, "dest", Option.I.arg, "pkg/*", Option.X.arg, "pkg/pkg/*", - Option.IF.arg, "root/pkg/MyClass1.java", - Option.XF.arg, "root/pkg/MyClass2.java", Option.SRC.arg, "root", Option.SOURCEPATH.arg, "sourcepath", Option.CLASSPATH.arg, "classpath", @@ -87,8 +85,6 @@ assertEquals(sl1.getPath(), sl2.getPath()); assertEquals(sl1.getIncludes(), sl2.getIncludes()); assertEquals(sl1.getExcludes(), sl2.getExcludes()); - assertEquals(sl1.getIncludedFiles(), sl2.getIncludedFiles()); - assertEquals(sl1.getExcludedFiles(), sl2.getExcludedFiles()); assertEquals(options1.getClassSearchPath(), options2.getClassSearchPath()); assertEquals(options1.getSourceSearchPaths(), options2.getSourceSearchPaths()); diff -r 3c05feabae49 -r 2dc4c11fe488 langtools/test/tools/sjavac/util/OptionTestUtil.java --- a/langtools/test/tools/sjavac/util/OptionTestUtil.java Wed Jul 05 21:12:06 2017 +0200 +++ b/langtools/test/tools/sjavac/util/OptionTestUtil.java Wed Jul 05 21:13:10 2017 +0200 @@ -62,9 +62,7 @@ if (!sl1.getPath().equals(sl2.getPath()) || !sl1.getIncludes().equals(sl2.getIncludes()) || - !sl1.getExcludes().equals(sl2.getExcludes()) || - !sl1.getIncludedFiles().equals(sl2.getIncludedFiles()) || - !sl1.getExcludedFiles().equals(sl2.getExcludedFiles())) + !sl1.getExcludes().equals(sl2.getExcludes())) throw new AssertionError("Expected " + sl1 + " but got " + sl2); } } diff -r 3c05feabae49 -r 2dc4c11fe488 make/common/JavaCompilation.gmk --- a/make/common/JavaCompilation.gmk Wed Jul 05 21:12:06 2017 +0200 +++ b/make/common/JavaCompilation.gmk Wed Jul 05 21:13:10 2017 +0200 @@ -202,23 +202,28 @@ # CacheFind does not preserve order so need to call it for each root. $1_ALL_SRCS += $$(foreach s, $$($1_SRC), $$(call CacheFind, $$(s))) # Extract the java files. - ifneq ($$($1_EXCLUDE_FILES),) - $1_EXCLUDE_FILES_PATTERN:=$$(addprefix %,$$($1_EXCLUDE_FILES)) + $1_SRCS := $$(filter %.java, $$($1_ALL_SRCS)) + + # Translate include/exclude into patterns + ifneq ($$($1_EXCLUDE_FILES), ) + $1_EXCLUDE_PATTERN := $$(addprefix %, $$($1_EXCLUDE_FILES)) endif - $1_SRCS := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$(filter %.java,$$($1_ALL_SRCS))) - ifneq ($$($1_INCLUDE_FILES),) - $1_INCLUDE_FILES:=$$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$($1_INCLUDE_FILES))) - $1_SRCS := $$(filter $$($1_INCLUDE_FILES), $$($1_SRCS)) + ifneq ($$($1_INCLUDE_FILES), ) + $1_INCLUDE_PATTERN := $$(foreach i, $$($1_SRC), $$(addprefix $$i/, $$($1_INCLUDE_FILES))) + endif + ifneq ($$($1_EXCLUDES), ) + $1_EXCLUDE_PATTERN += $$(foreach i, $$($1_SRC), $$(addprefix $$i/, $$(addsuffix /%, $$($1_EXCLUDES)))) + endif + ifneq ($$($1_INCLUDES), ) + $1_INCLUDE_PATTERN += $$(foreach i, $$($1_SRC), $$(addprefix $$i/, $$(addsuffix /%, $$($1_INCLUDES)))) endif - # Prepend the source/bin path to the filter expressions. - ifneq ($$($1_INCLUDES),) - $1_SRC_INCLUDES := $$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$(addsuffix /%,$$($1_INCLUDES)))) - $1_SRCS := $$(filter $$($1_SRC_INCLUDES),$$($1_SRCS)) + # Apply include/exclude patterns to java sources + ifneq ($$($1_EXCLUDE_PATTERN), ) + $1_SRCS := $$(filter-out $$($1_EXCLUDE_PATTERN), $$($1_SRCS)) endif - ifneq ($$($1_EXCLUDES),) - $1_SRC_EXCLUDES := $$(foreach i,$$($1_SRC),$$(addprefix $$i/,$$(addsuffix /%,$$($1_EXCLUDES)))) - $1_SRCS := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_SRCS)) + ifneq ($$($1_INCLUDE_PATTERN), ) + $1_SRCS := $$(filter $$($1_INCLUDE_PATTERN), $$($1_SRCS)) endif ifneq ($$($1_KEEP_DUPS), true) @@ -242,10 +247,10 @@ $1_SAFE_NAME := $$(strip $$(subst /,_, $1)) # Create the corresponding smart javac wrapper command line. - $1_SJAVAC_ARGS:=$$(addprefix -x ,$$(addsuffix /*,$$($1_EXCLUDES))) \ - $$(addprefix -i ,$$(addsuffix /*,$$($1_INCLUDES))) \ - $$(addprefix -xf *,$$(strip $$($1_EXCLUDE_FILES) $$($1_SJAVAC_EXCLUDE_FILES))) \ - $$(addprefix -if *,$$(strip $$($1_INCLUDE_FILES))) \ + $1_SJAVAC_ARGS:=$$(addprefix -x ,$$(addsuffix /**,$$($1_EXCLUDES))) \ + $$(addprefix -i ,$$(addsuffix /**,$$($1_INCLUDES))) \ + $$(addprefix -x **,$$(strip $$($1_EXCLUDE_FILES) $$($1_SJAVAC_EXCLUDE_FILES))) \ + $$(addprefix -i **,$$(strip $$($1_INCLUDE_FILES))) \ -src $$(call PathList, $$($1_SRC)) # All files below META-INF are always copied. @@ -258,14 +263,11 @@ $1_ALL_COPIES += $$($1_COPY_FILES) endif # Copy must also respect filters. - ifneq (,$$($1_INCLUDES)) - $1_ALL_COPIES := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_COPIES)) + ifneq (,$$($1_INCLUDE_PATTERN)) + $1_ALL_COPIES := $$(filter $$($1_INCLUDE_PATTERN),$$($1_ALL_COPIES)) endif - ifneq (,$$($1_EXCLUDES)) - $1_ALL_COPIES := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_ALL_COPIES)) - endif - ifneq (,$$($1_EXCLUDE_FILES)) - $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_COPIES)) + ifneq (,$$($1_EXCLUDE_PATTERN)) + $1_ALL_COPIES := $$(filter-out $$($1_EXCLUDE_PATTERN),$$($1_ALL_COPIES)) endif ifneq (,$$($1_ALL_COPIES)) # Yep, there are files to be copied! @@ -281,14 +283,11 @@ # Clean these explicitly $1_ALL_CLEANS += $$($1_CLEAN_FILES) # Copy and clean must also respect filters. - ifneq (,$$($1_INCLUDES)) - $1_ALL_CLEANS := $$(filter $$($1_SRC_INCLUDES),$$($1_ALL_CLEANS)) + ifneq (,$$($1_INCLUDE_PATTERN)) + $1_ALL_CLEANS := $$(filter $$($1_INCLUDE_PATTERN),$$($1_ALL_CLEANS)) endif - ifneq (,$$($1_EXCLUDES)) - $1_ALL_CLEANS := $$(filter-out $$($1_SRC_EXCLUDES),$$($1_ALL_CLEANS)) - endif - ifneq (,$$($1_EXCLUDE_FILES)) - $1_ALL_CLEANS := $$(filter-out $$($1_EXCLUDE_FILES_PATTERN),$$($1_ALL_CLEANS)) + ifneq (,$$($1_EXCLUDE_PATTERN)) + $1_ALL_CLEANS := $$(filter-out $$($1_EXCLUDE_PATTERN),$$($1_ALL_CLEANS)) endif ifneq (,$$($1_ALL_CLEANS)) # Yep, there are files to be copied and cleaned! diff -r 3c05feabae49 -r 2dc4c11fe488 modules.xml --- a/modules.xml Wed Jul 05 21:12:06 2017 +0200 +++ b/modules.xml Wed Jul 05 21:13:10 2017 +0200 @@ -239,6 +239,12 @@ jdk.scripting.nashorn + jdk.internal.perf + java.desktop + java.management + jdk.jvmstat + + jdk.internal.org.objectweb.asm java.instrument jdk.jfr diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/.hgtags --- a/nashorn/.hgtags Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/.hgtags Wed Jul 05 21:13:10 2017 +0200 @@ -334,3 +334,4 @@ 68a36216f70c0de4c7e36f8978995934fc72ec03 jdk-9+98 74ddd1339c57cf2c2a13e34e1760006c2e54d1fc jdk-9+99 da397aea8adad7e6f743b60bfe0c415fc8508df5 jdk-9+100 +1916a2c680d8c33b59943dbb6dc2dd2000ec821a jdk-9+101 diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -349,55 +349,121 @@ throws Exception { final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor(); + final MissingMemberHandlerFactory missingMemberHandlerFactory; + final LinkerServices directLinkerServices; + if (linkerServices instanceof LinkerServicesWithMissingMemberHandlerFactory) { + final LinkerServicesWithMissingMemberHandlerFactory lswmmhf = ((LinkerServicesWithMissingMemberHandlerFactory)linkerServices); + missingMemberHandlerFactory = lswmmhf.missingMemberHandlerFactory; + directLinkerServices = lswmmhf.linkerServices; + } else { + missingMemberHandlerFactory = null; + directLinkerServices = linkerServices; + } + // Handle NamedOperation(CALL_METHOD, name) separately final Operation operation = callSiteDescriptor.getOperation(); if (operation instanceof NamedOperation) { final NamedOperation namedOperation = (NamedOperation)operation; if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) { - return createGuardedDynamicMethodInvocation(callSiteDescriptor, - linkerServices, namedOperation.getName().toString(), methods); + final GuardedInvocation inv = + createGuardedDynamicMethodInvocation(callSiteDescriptor, + directLinkerServices, namedOperation.getName().toString(), methods); + if (inv == null) { + return createNoSuchMemberHandler(missingMemberHandlerFactory, + request, directLinkerServices).getGuardedInvocation(); + } + return inv; } } - List operations = Arrays.asList( - CompositeOperation.getOperations( - NamedOperation.getBaseOperation(operation))); - final Object name = NamedOperation.getName(operation); + final GuardedInvocationComponent gic = getGuardedInvocationComponent( + new ComponentLinkRequest(request, directLinkerServices, + missingMemberHandlerFactory)); + return gic != null ? gic.getGuardedInvocation() : null; + } + + static final class ComponentLinkRequest { + final LinkRequest linkRequest; + final LinkerServices linkerServices; + final MissingMemberHandlerFactory missingMemberHandlerFactory; + final List operations; + final Object name; + + ComponentLinkRequest(final LinkRequest linkRequest, + final LinkerServices linkerServices, + final MissingMemberHandlerFactory missingMemberHandlerFactory) { + this.linkRequest = linkRequest; + this.linkerServices = linkerServices; + this.missingMemberHandlerFactory = missingMemberHandlerFactory; + final Operation operation = linkRequest.getCallSiteDescriptor().getOperation(); + this.operations = Arrays.asList( + CompositeOperation.getOperations( + NamedOperation.getBaseOperation(operation))); + this.name = NamedOperation.getName(operation); + } - while(!operations.isEmpty()) { - final GuardedInvocationComponent gic = - getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, name); - if(gic != null) { - return gic.getGuardedInvocation(); + private ComponentLinkRequest(final LinkRequest linkRequest, + final LinkerServices linkerServices, + final MissingMemberHandlerFactory missingMemberHandlerFactory, + final List operations, final Object name) { + this.linkRequest = linkRequest; + this.linkerServices = linkerServices; + this.missingMemberHandlerFactory = missingMemberHandlerFactory; + this.operations = operations; + this.name = name; + } + + CallSiteDescriptor getDescriptor() { + return linkRequest.getCallSiteDescriptor(); + } + + ComponentLinkRequest popOperations() { + return new ComponentLinkRequest(linkRequest, linkerServices, + missingMemberHandlerFactory, + operations.subList(1, operations.size()), name); + } + } + + protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) + throws Exception { + final Operation op = req.operations.get(0); + if (op instanceof StandardOperation) { + switch((StandardOperation)op) { + case GET_PROPERTY: return getPropertyGetter(req.popOperations()); + case SET_PROPERTY: return getPropertySetter(req.popOperations()); + case GET_METHOD: return getMethodGetter(req.popOperations()); + default: } - operations = pop(operations); } return null; } - protected GuardedInvocationComponent getGuardedInvocationComponent( - final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, - final List operations, final Object name) - throws Exception { - if(operations.isEmpty()) { + GuardedInvocationComponent getNextComponent(final ComponentLinkRequest req) throws Exception { + if (req.operations.isEmpty()) { + return createNoSuchMemberHandler(req.missingMemberHandlerFactory, + req.linkRequest, req.linkerServices); + } + final GuardedInvocationComponent gic = getGuardedInvocationComponent(req); + if (gic != null) { + return gic; + } + return getNextComponent(req.popOperations()); + } + + private GuardedInvocationComponent createNoSuchMemberHandler( + final MissingMemberHandlerFactory missingMemberHandlerFactory, + final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + if (missingMemberHandlerFactory == null) { return null; } - final Operation op = operations.get(0); - // Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name) - if(op == StandardOperation.GET_PROPERTY) { - return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name); + final MethodHandle handler = missingMemberHandlerFactory.createMissingMemberHandler(linkRequest, linkerServices); + if (handler == null) { + return null; } - // Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value) - if(op == StandardOperation.SET_PROPERTY) { - return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name); - } - // Either GET_METHOD:name(this), or GET_METHOD(this, name) - if(op == StandardOperation.GET_METHOD) { - return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name); - } - return null; + final MethodType type = linkRequest.getCallSiteDescriptor().getMethodType(); + // The returned handler is allowed to differ in return type. + assert handler.type().changeReturnType(type.returnType()).equals(type); + return getClassGuardedInvocationComponent(handler, type); } static final List pop(final List l) { @@ -483,16 +549,15 @@ private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments( MethodHandles.constant(Object.class, null), 0, MethodHandle.class); - private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { - if (name == null) { - return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations); + private GuardedInvocationComponent getPropertySetter(final ComponentLinkRequest req) throws Exception { + if (req.name == null) { + return getUnnamedPropertySetter(req); } - return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name); + return getNamedPropertySetter(req); } - private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations) throws Exception { + private GuardedInvocationComponent getUnnamedPropertySetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.getDescriptor(); // Must have three arguments: target object, property name, and property value. assertParameterCount(callSiteDescriptor, 3); @@ -501,6 +566,7 @@ // invoked, we'll conservatively presume Object return type. The one exception is void return. final MethodType origType = callSiteDescriptor.getMethodType(); final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class); + final LinkerServices linkerServices = req.linkerServices; // What's below is basically: // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation), @@ -527,11 +593,10 @@ // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V) final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType( 1)); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, null); + final GuardedInvocationComponent nextComponent = getNextComponent(req); final MethodHandle fallbackFolded; - if(nextComponent == null) { + if (nextComponent == null) { // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1, type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class)); @@ -551,19 +616,19 @@ return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } - private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + private GuardedInvocationComponent getNamedPropertySetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.getDescriptor(); // Must have two arguments: target object and property value assertParameterCount(callSiteDescriptor, 2); - final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices, - name.toString(), propertySetters); + final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, req.linkerServices, + req.name.toString(), propertySetters); // If we have a property setter with this name, this composite operation will always stop here if(gi != null) { return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS); } // If we don't have a property setter with this name, always fall back to the next operation in the // composite (if any) - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name); + return getNextComponent(req); } private static final Lookup privateLookup = new Lookup(MethodHandles.lookup()); @@ -576,20 +641,18 @@ "getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class)); private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)); - private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final Object name) throws Exception { - if (name == null) { - return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops); + private GuardedInvocationComponent getPropertyGetter(final ComponentLinkRequest req) throws Exception { + if (req.name == null) { + return getUnnamedPropertyGetter(req); } - - return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name); + return getNamedPropertyGetter(req); } - private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops) throws Exception { + private GuardedInvocationComponent getUnnamedPropertyGetter(final ComponentLinkRequest req) throws Exception { // Since we can't know what kind of a getter we'll get back on different invocations, we'll just // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking // runtime might not allow coercing at that call site. + final CallSiteDescriptor callSiteDescriptor = req.getDescriptor(); final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); // Must have exactly two arguments: receiver and name assertParameterCount(callSiteDescriptor, 2); @@ -600,6 +663,7 @@ // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null, // or delegate to next component's invocation. + final LinkerServices linkerServices = req.linkerServices; final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType( AnnotatedDynamicMethod.class)); final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments( @@ -613,8 +677,7 @@ // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1) final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2, type.parameterType(1)); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, ops, null); + final GuardedInvocationComponent nextComponent = getNextComponent(req); final MethodHandle fallbackFolded; if(nextComponent == null) { @@ -639,17 +702,17 @@ return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } - private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final Object name) throws Exception { + private GuardedInvocationComponent getNamedPropertyGetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.getDescriptor(); // Must have exactly one argument: receiver assertParameterCount(callSiteDescriptor, 1); // Fixed name - final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString()); + final AnnotatedDynamicMethod annGetter = propertyGetters.get(req.name.toString()); if(annGetter == null) { // We have no such property, always delegate to the next component operation - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); + return getNextComponent(req); } - final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices); + final MethodHandle getter = annGetter.getInvocation(req); // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If @@ -686,28 +749,27 @@ MethodType.methodType(boolean.class, Object.class)); private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class); - private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final Object name) throws Exception { + private GuardedInvocationComponent getMethodGetter(final ComponentLinkRequest req) throws Exception { + if (req.name == null) { + return getUnnamedMethodGetter(req); + } + return getNamedMethodGetter(req); + } + + private static MethodType getMethodGetterType(final ComponentLinkRequest req) { // The created method handle will always return a DynamicMethod (or null), but since we don't want that type to // be visible outside of this linker, declare it to return Object. - final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class); - if (name == null) { - return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type); - } - - return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type); + return req.getDescriptor().getMethodType().changeReturnType(Object.class); } - private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final MethodType type) throws Exception { + private GuardedInvocationComponent getUnnamedMethodGetter(final ComponentLinkRequest req) throws Exception { // Must have exactly two arguments: receiver and name - assertParameterCount(callSiteDescriptor, 2); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, ops, null); - if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class, - nextComponent.getGuardedInvocation().getInvocation().type().returnType())) { - // No next component operation, or it can never produce a dynamic method; just return a component - // for this operation. + assertParameterCount(req.getDescriptor(), 2); + final GuardedInvocationComponent nextComponent = getNextComponent(req); + final LinkerServices linkerServices = req.linkerServices; + final MethodType type = getMethodGetterType(req); + if(nextComponent == null) { + // No next component operation; just return a component for this operation. return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type); } @@ -728,25 +790,28 @@ final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0, Object.class); // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get) + // Note that nextCombinedInvocation needs to have its return type changed to Object final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest( - IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter); + IS_DYNAMIC_METHOD, returnMethodHandle, + nextCombinedInvocation.asType(nextCombinedInvocation.type().changeReturnType(Object.class))), + typedGetter); return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS); } - private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final Object name, final MethodType type) + private GuardedInvocationComponent getNamedMethodGetter(final ComponentLinkRequest req) throws Exception { // Must have exactly one argument: receiver - assertParameterCount(callSiteDescriptor, 1); - final DynamicMethod method = getDynamicMethod(name.toString()); + assertParameterCount(req.getDescriptor(), 1); + final DynamicMethod method = getDynamicMethod(req.name.toString()); if(method == null) { // We have no such method, always delegate to the next component - return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name); + return getNextComponent(req); } // No delegation to the next component of the composite operation; if we have a method with that name, // we'll always return it at this point. - return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments( + final MethodType type = getMethodGetterType(req); + return getClassGuardedInvocationComponent(req.linkerServices.asType(MethodHandles.dropArguments( MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type); } @@ -876,8 +941,8 @@ this.validationType = validationType; } - MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) { - return method.getInvocation(callSiteDescriptor, linkerServices); + MethodHandle getInvocation(final ComponentLinkRequest req) { + return method.getInvocation(req.getDescriptor(), req.linkerServices); } @SuppressWarnings("unused") diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -88,6 +88,7 @@ import java.lang.invoke.MethodType; import java.lang.reflect.Array; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import jdk.dynalink.CallSiteDescriptor; @@ -129,25 +130,21 @@ } @Override - protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { - final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, name); + protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception { + final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(req); if(superGic != null) { return superGic; } - if(operations.isEmpty()) { - return null; - } - final Operation op = operations.get(0); - if(op == StandardOperation.GET_ELEMENT) { - return getElementGetter(callSiteDescriptor, linkerServices, pop(operations), name); - } - if(op == StandardOperation.SET_ELEMENT) { - return getElementSetter(callSiteDescriptor, linkerServices, pop(operations), name); - } - if(op == StandardOperation.GET_LENGTH) { - return getLengthGetter(callSiteDescriptor); + if (!req.operations.isEmpty()) { + final Operation op = req.operations.get(0); + if (op instanceof StandardOperation) { + switch ((StandardOperation)op) { + case GET_ELEMENT: return getElementGetter(req.popOperations()); + case SET_ELEMENT: return getElementSetter(req.popOperations()); + case GET_LENGTH: return getLengthGetter(req.getDescriptor()); + default: + } + } } return null; } @@ -166,16 +163,31 @@ private static final MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class); private static final MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class); + private static final MethodHandle NULL_GETTER_1; + private static final MethodHandle NULL_GETTER_2; + static { + final MethodHandle constantNull = MethodHandles.constant(Object.class, null); + NULL_GETTER_1 = dropObjectArguments(constantNull, 1); + NULL_GETTER_2 = dropObjectArguments(constantNull, 2); + } + + private static MethodHandle dropObjectArguments(final MethodHandle m, final int n) { + return MethodHandles.dropArguments(m, 0, Collections.nCopies(n, Object.class)); + } + private enum CollectionType { ARRAY, LIST, MAP }; - private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + private GuardedInvocationComponent getElementGetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.getDescriptor(); + final Object name = req.name; + final boolean isFixedKey = name != null; + assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2); + final LinkerServices linkerServices = req.linkerServices; final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class declaredType = callSiteType.parameterType(0); - final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, name); + final GuardedInvocationComponent nextComponent = getNextComponent(req); // If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing // is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're @@ -211,12 +223,14 @@ // Convert the key to a number if we're working with a list or array final Object typedName; - if(collectionType != CollectionType.MAP && name != null) { - typedName = convertKeyToInteger(name, linkerServices); - if(typedName == null) { - // key is not numeric, it can never succeed + if (collectionType != CollectionType.MAP && isFixedKey) { + final Integer integer = convertKeyToInteger(name, linkerServices); + if (integer == null || integer.intValue() < 0) { + // key is not a non-negative integer, it can never address an + // array or list element return nextComponent; } + typedName = integer; } else { typedName = name; } @@ -225,30 +239,33 @@ final Binder binder = new Binder(linkerServices, callSiteType, typedName); final MethodHandle invocation = gi.getInvocation(); - if(nextComponent == null) { - return gic.replaceInvocation(binder.bind(invocation)); - } - final MethodHandle checkGuard; switch(collectionType) { case LIST: - checkGuard = convertArgToInt(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor); + checkGuard = convertArgToNumber(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor); break; case MAP: - // TODO: A more complex solution could be devised for maps, one where we do a get() first, and fold it - // into a GWT that tests if it returned null, and if it did, do another GWT with containsKey() - // that returns constant null (on true), or falls back to next component (on false) checkGuard = linkerServices.filterInternalObjects(CONTAINS_MAP); break; case ARRAY: - checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); + checkGuard = convertArgToNumber(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); break; default: throw new AssertionError(); } + + // If there's no next component, produce a fixed null-returning one + final GuardedInvocationComponent finalNextComponent; + if (nextComponent != null) { + finalNextComponent = nextComponent; + } else { + final MethodHandle nullGetterHandle = isFixedKey ? NULL_GETTER_1 : NULL_GETTER_2; + finalNextComponent = createGuardedInvocationComponentAsType(nullGetterHandle, callSiteType, linkerServices); + } + final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation), - nextComponent.getGuardedInvocation().getInvocation()); - return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(), + finalNextComponent.getGuardedInvocation().getInvocation()); + return finalNextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(), gic.getValidatorClass(), gic.getValidationType()); } @@ -257,6 +274,11 @@ return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation)); } + private static GuardedInvocationComponent createGuardedInvocationComponentAsType( + final MethodHandle invocation, final MethodType fromType, final LinkerServices linkerServices) { + return new GuardedInvocationComponent(linkerServices.asType(invocation, fromType)); + } + private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent( final MethodHandle invocation, final MethodHandle guard, final Class validatorClass, final ValidationType validationType, final LinkerServices linkerServices) { @@ -310,7 +332,7 @@ return intIndex; } - private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) { + private static MethodHandle convertArgToNumber(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) { final Class sourceType = desc.getMethodType().parameterType(1); if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) { return mh; @@ -366,14 +388,10 @@ } final Number n = (Number)index; final int intIndex = n.intValue(); - final double doubleValue = n.doubleValue(); - if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE + if (intIndex != n.doubleValue()) { return false; } - if(0 <= intIndex && intIndex < Array.getLength(array)) { - return true; - } - throw new ArrayIndexOutOfBoundsException("Array index out of range: " + n); + return 0 <= intIndex && intIndex < Array.getLength(array); } @SuppressWarnings("unused") @@ -383,14 +401,14 @@ } final Number n = (Number)index; final int intIndex = n.intValue(); - final double doubleValue = n.doubleValue(); - if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE + if (intIndex != n.doubleValue()) { return false; } - if(0 <= intIndex && intIndex < list.size()) { - return true; - } - throw new IndexOutOfBoundsException("Index: " + n + ", Size: " + list.size()); + return 0 <= intIndex && intIndex < list.size(); + } + + @SuppressWarnings("unused") + private static void noOpSetter() { } private static final MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set", @@ -399,8 +417,20 @@ private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put", MethodType.methodType(Object.class, Object.class, Object.class)); - private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List operations, final Object name) throws Exception { + private static final MethodHandle NO_OP_SETTER_2; + private static final MethodHandle NO_OP_SETTER_3; + static { + final MethodHandle noOpSetter = Lookup.findOwnStatic(MethodHandles.lookup(), "noOpSetter", void.class); + NO_OP_SETTER_2 = dropObjectArguments(noOpSetter, 2); + NO_OP_SETTER_3 = dropObjectArguments(noOpSetter, 3); + } + + private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception { + final CallSiteDescriptor callSiteDescriptor = req.getDescriptor(); + final Object name = req.name; + final boolean isFixedKey = name != null; + assertParameterCount(callSiteDescriptor, isFixedKey ? 2 : 3); + final LinkerServices linkerServices = req.linkerServices; final MethodType callSiteType = callSiteDescriptor.getMethodType(); final Class declaredType = callSiteType.parameterType(0); @@ -441,20 +471,21 @@ // In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map, // as maps will always succeed in setting the element and will never need to fall back to the next component // operation. - final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent( - callSiteDescriptor, linkerServices, operations, name); + final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getNextComponent(req); if(gic == null) { return nextComponent; } // Convert the key to a number if we're working with a list or array final Object typedName; - if(collectionType != CollectionType.MAP && name != null) { - typedName = convertKeyToInteger(name, linkerServices); - if(typedName == null) { - // key is not numeric, it can never succeed + if (collectionType != CollectionType.MAP && isFixedKey) { + final Integer integer = convertKeyToInteger(name, linkerServices); + if (integer == null || integer.intValue() < 0) { + // key is not a non-negative integer, it can never address an + // array or list element return nextComponent; } + typedName = integer; } else { typedName = name; } @@ -463,16 +494,27 @@ final Binder binder = new Binder(linkerServices, callSiteType, typedName); final MethodHandle invocation = gi.getInvocation(); - if(nextComponent == null) { + if (collectionType == CollectionType.MAP) { + assert nextComponent == null; return gic.replaceInvocation(binder.bind(invocation)); } assert collectionType == CollectionType.LIST || collectionType == CollectionType.ARRAY; - final MethodHandle checkGuard = convertArgToInt(collectionType == CollectionType.LIST ? RANGE_CHECK_LIST : + final MethodHandle checkGuard = convertArgToNumber(collectionType == CollectionType.LIST ? RANGE_CHECK_LIST : RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor); + + // If there's no next component, produce a no-op one. + final GuardedInvocationComponent finalNextComponent; + if (nextComponent != null) { + finalNextComponent = nextComponent; + } else { + final MethodHandle noOpSetterHandle = isFixedKey ? NO_OP_SETTER_2 : NO_OP_SETTER_3; + finalNextComponent = createGuardedInvocationComponentAsType(noOpSetterHandle, callSiteType, linkerServices); + } + final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation), - nextComponent.getGuardedInvocation().getInvocation()); - return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(), + finalNextComponent.getGuardedInvocation().getInvocation()); + return finalNextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(), gic.getValidatorClass(), gic.getValidationType()); } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -146,7 +146,11 @@ * are otherwise public and link requests have call site descriptors carrying * full-strength {@link Lookup} objects and not weakened lookups or the public * lookup.

- *

The class also exposes various static methods for discovery of available + *

The behavior for handling missing members can be + * customized by passing a {@link MissingMemberHandlerFactory} to the + * {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory) constructor}. + *

+ *

The class also exposes various methods for discovery of available * property and method names on classes and class instances, as well as access * to per-class linkers using the {@link #getLinkerForClass(Class)} * method.

@@ -164,10 +168,27 @@ } }; + private final MissingMemberHandlerFactory missingMemberHandlerFactory; + /** - * Creates a new beans linker. + * Creates a new beans linker. Equivalent to + * {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory)} with + * {@code null} passed as the missing member handler factory, resulting in + * the default behavior for linking and evaluating missing members. */ public BeansLinker() { + this(null); + } + + /** + * Creates a new beans linker with the specified factory for creating + * missing member handlers. The passed factory can be null if the default + * behavior is adequate. See {@link MissingMemberHandlerFactory} for details. + * @param missingMemberHandlerFactory a factory for creating handlers for + * operations on missing members. + */ + public BeansLinker(final MissingMemberHandlerFactory missingMemberHandlerFactory) { + this.missingMemberHandlerFactory = missingMemberHandlerFactory; } /** @@ -178,7 +199,37 @@ * @param clazz the class * @return a bean linker for that class */ - public static TypeBasedGuardingDynamicLinker getLinkerForClass(final Class clazz) { + public TypeBasedGuardingDynamicLinker getLinkerForClass(final Class clazz) { + final TypeBasedGuardingDynamicLinker staticLinker = getStaticLinkerForClass(clazz); + if (missingMemberHandlerFactory == null) { + return staticLinker; + } + return new NoSuchMemberHandlerBindingLinker(staticLinker, missingMemberHandlerFactory); + } + + private static class NoSuchMemberHandlerBindingLinker implements TypeBasedGuardingDynamicLinker { + private final TypeBasedGuardingDynamicLinker linker; + private final MissingMemberHandlerFactory missingMemberHandlerFactory; + + NoSuchMemberHandlerBindingLinker(final TypeBasedGuardingDynamicLinker linker, final MissingMemberHandlerFactory missingMemberHandlerFactory) { + this.linker = linker; + this.missingMemberHandlerFactory = missingMemberHandlerFactory; + } + + @Override + public boolean canLinkType(final Class type) { + return linker.canLinkType(type); + } + + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + return linker.getGuardedInvocation(linkRequest, + LinkerServicesWithMissingMemberHandlerFactory.get( + linkerServices, missingMemberHandlerFactory)); + } + } + + static TypeBasedGuardingDynamicLinker getStaticLinkerForClass(final Class clazz) { return linkers.get(clazz); } @@ -234,7 +285,7 @@ * @return a set of names of all readable instance properties of a class. */ public static Set getReadableInstancePropertyNames(final Class clazz) { - final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz); if(linker instanceof BeanLinker) { return ((BeanLinker)linker).getReadablePropertyNames(); } @@ -247,7 +298,7 @@ * @return a set of names of all writable instance properties of a class. */ public static Set getWritableInstancePropertyNames(final Class clazz) { - final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz); if(linker instanceof BeanLinker) { return ((BeanLinker)linker).getWritablePropertyNames(); } @@ -260,7 +311,7 @@ * @return a set of names of all instance methods of a class. */ public static Set getInstanceMethodNames(final Class clazz) { - final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz); + final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz); if(linker instanceof BeanLinker) { return ((BeanLinker)linker).getMethodNames(); } @@ -302,6 +353,8 @@ // Can't operate on null return null; } - return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request, linkerServices); + return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request, + LinkerServicesWithMissingMemberHandlerFactory.get(linkerServices, + missingMemberHandlerFactory)); } } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/LinkerServicesWithMissingMemberHandlerFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/LinkerServicesWithMissingMemberHandlerFactory.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import jdk.dynalink.linker.ConversionComparator.Comparison; +import jdk.dynalink.linker.GuardedInvocation; +import jdk.dynalink.linker.LinkRequest; +import jdk.dynalink.linker.LinkerServices; + +final class LinkerServicesWithMissingMemberHandlerFactory implements LinkerServices { + final LinkerServices linkerServices; + final MissingMemberHandlerFactory missingMemberHandlerFactory; + + static LinkerServices get(final LinkerServices linkerServices, final MissingMemberHandlerFactory missingMemberHandlerFactory) { + if (missingMemberHandlerFactory == null) { + return linkerServices; + } + return new LinkerServicesWithMissingMemberHandlerFactory(linkerServices, missingMemberHandlerFactory); + } + + private LinkerServicesWithMissingMemberHandlerFactory(final LinkerServices linkerServices, final MissingMemberHandlerFactory missingMemberHandlerFactory) { + this.linkerServices = linkerServices; + this.missingMemberHandlerFactory = missingMemberHandlerFactory; + } + + @Override + public MethodHandle asType(final MethodHandle handle, final MethodType fromType) { + return linkerServices.asType(handle, fromType); + } + + @Override + public MethodHandle getTypeConverter(final Class sourceType, final Class targetType) { + return linkerServices.getTypeConverter(sourceType, targetType); + } + + @Override + public boolean canConvert(final Class from, final Class to) { + return linkerServices.canConvert(from, to); + } + + @Override + public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception { + return linkerServices.getGuardedInvocation(linkRequest); + } + + @Override + public Comparison compareConversion(final Class sourceType, final Class targetType1, final Class targetType2) { + return linkerServices.compareConversion(sourceType, targetType1, targetType2); + } + + @Override + public MethodHandle filterInternalObjects(final MethodHandle target) { + return linkerServices.filterInternalObjects(target); + } +} diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.dynalink.beans; + +import java.lang.invoke.MethodHandle; +import jdk.dynalink.DynamicLinkerFactory; +import jdk.dynalink.NamedOperation; +import jdk.dynalink.NoSuchDynamicMethodException; +import jdk.dynalink.StandardOperation; +import jdk.dynalink.linker.LinkRequest; +import jdk.dynalink.linker.LinkerServices; + +/** + * A factory for creating method handles for linking missing member behavior + * in {@link BeansLinker}. BeansLinker links these method handles into guarded + * invocations for link requests specifying {@code GET_*} and {@code SET_*} + * {@link StandardOperation}s when it is either certain or possible that the + * requested member (property, method, or element) is missing. They will be + * linked both for {@link NamedOperation named} and unnamed operations. The + * implementer must ensure that the parameter types of the returned method + * handle match the parameter types of the call site described in the link + * request. The return types can differ, though, to allow + * {@link DynamicLinkerFactory#setPrelinkTransformer(jdk.dynalink.linker.GuardedInvocationTransformer)} + * late return type transformations}. It is allowed to return {@code null} for a + * method handle if the default behavior is sufficient. + *

Default missing member behavior

+ * When a {@link BeansLinker} is configured without a missing member handler + * factory, or the factory returns {@code null} for a particular handler + * creation invocation, the default behavior is used. The default behavior is to + * return {@code null} from + * {@link BeansLinker#getGuardedInvocation(LinkRequest, LinkerServices)} when it + * can be determined at link time that the linked operation will never address + * an existing member. This lets the {@code DynamicLinker} attempt the next + * linker if there is one, or ultimately fail the link request with + * {@link NoSuchDynamicMethodException}. For other cases (typically all unnamed + * member operations as well as most named operations on collection elements) + * {@code BeansLinker} will produce a conditional linkage that will return + * {@code null} when invoked at runtime with a name that does not match any + * member for getters and silently ignore the passed values for setters. + *

Implementing exception-throwing behavior

+ * Note that if the language-specific behavior for an operation on a missing + * member is to throw an exception then the factory should produce a method + * handle that throws the exception when invoked, and must not throw an + * exception itself, as the linkage for the missing member is often conditional. + * + * @see BeansLinker#BeansLinker(MissingMemberHandlerFactory) + */ +@FunctionalInterface +public interface MissingMemberHandlerFactory { + /** + * Returns a method handle suitable for implementing missing member behavior + * for a particular link request. See the class description for details. + * @param linkRequest the current link request + * @param linkerServices the current link services + * @return a method handle that can be invoked if the property, element, or + * method being addressed by an operation is missing. The return value can + * be null. + * @throws Exception if the operation fails for any reason. Please observe + * the class documentation notes for implementing exception-throwing + * missing member behavior. + */ + public MethodHandle createMissingMemberHandler(LinkRequest linkRequest, LinkerServices linkerServices) throws Exception; +} diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -91,6 +91,7 @@ import java.util.Set; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; +import jdk.dynalink.Operation; import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType; import jdk.dynalink.linker.GuardedInvocation; @@ -162,6 +163,27 @@ } @Override + protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception { + final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(req); + if (superGic != null) { + return superGic; + } + if (!req.operations.isEmpty()) { + final Operation op = req.operations.get(0); + if (op instanceof StandardOperation) { + switch ((StandardOperation)op) { + case GET_ELEMENT: + case SET_ELEMENT: + // StaticClass doesn't behave as a collection + return getNextComponent(req.popOperations()); + default: + } + } + } + return null; + } + + @Override SingleDynamicMethod getConstructorMethod(final String signature) { return constructor != null? constructor.getMethodForExactParamTypes(signature) : null; } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java Wed Jul 05 21:13:10 2017 +0200 @@ -202,6 +202,9 @@ this.invocation = Objects.requireNonNull(invocation); this.guard = guard; this.switchPoints = switchPoint == null ? null : new SwitchPoint[] { switchPoint }; + if (exception != null && !Throwable.class.isAssignableFrom(exception)) { + throw new IllegalArgumentException(exception.getName() + " is not assignable from Throwable"); + } this.exception = exception; } @@ -228,6 +231,9 @@ this.invocation = Objects.requireNonNull(invocation); this.guard = guard; this.switchPoints = switchPoints == null ? null : switchPoints.clone(); + if (exception != null && !Throwable.class.isAssignableFrom(exception)) { + throw new IllegalArgumentException(exception.getName() + " is not assignable from Throwable"); + } this.exception = exception; } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Wed Jul 05 21:13:10 2017 +0200 @@ -1133,6 +1133,8 @@ return NativeNumber.lookupPrimitive(request, self); } else if (self instanceof Boolean) { return NativeBoolean.lookupPrimitive(request, self); + } else if (self instanceof Symbol) { + return NativeSymbol.lookupPrimitive(request, self); } throw new IllegalArgumentException("Unsupported primitive: " + self); } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Wed Jul 05 21:13:10 2017 +0200 @@ -284,8 +284,8 @@ // Step 3c and 3d - get new length and convert to long final long newLen = NativeArray.validLength(newLenDesc.getValue()); - // Step 3e - newLenDesc.setValue(newLen); + // Step 3e - note that we need to convert to int or double as long is not considered a JS number type anymore + newLenDesc.setValue(JSType.isRepresentableAsInt(newLen) ? Integer.valueOf((int) newLen) : Double.valueOf((double) newLen)); // Step 3f // increasing array length - just need to set new length value (and attributes if any) and return @@ -918,21 +918,6 @@ * @throws ClassCastException if array is empty, facilitating Undefined return value */ @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class) - public static long popLong(final Object self) { - //must be non empty Int or LongArrayData - return getContinuousNonEmptyArrayDataCCE(self, IntOrLongElements.class).fastPopLong(); - } - - /** - * Specialization of pop for ContinuousArrayData - * - * Primitive specialization, {@link LinkLogic} - * - * @param self self reference - * @return element popped - * @throws ClassCastException if array is empty, facilitating Undefined return value - */ - @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class) public static double popDouble(final Object self) { //must be non empty int long or double array data return getContinuousNonEmptyArrayDataCCE(self, NumericElements.class).fastPopDouble(); @@ -997,7 +982,7 @@ * @return array length after push */ @SpecializedFunction(linkLogic=PushLinkLogic.class) - public static long push(final Object self, final int arg) { + public static double push(final Object self, final int arg) { return getContinuousArrayDataCCE(self, Integer.class).fastPush(arg); } @@ -1011,7 +996,7 @@ * @return array length after push */ @SpecializedFunction(linkLogic=PushLinkLogic.class) - public static long push(final Object self, final long arg) { + public static double push(final Object self, final long arg) { return getContinuousArrayDataCCE(self, Long.class).fastPush(arg); } @@ -1025,7 +1010,7 @@ * @return array length after push */ @SpecializedFunction(linkLogic=PushLinkLogic.class) - public static long push(final Object self, final double arg) { + public static double push(final Object self, final double arg) { return getContinuousArrayDataCCE(self, Double.class).fastPush(arg); } @@ -1039,7 +1024,7 @@ * @return array length after push */ @SpecializedFunction(name="push", linkLogic=PushLinkLogic.class) - public static long pushObject(final Object self, final Object arg) { + public static double pushObject(final Object self, final Object arg) { return getContinuousArrayDataCCE(self, Object.class).fastPush(arg); } @@ -1081,7 +1066,7 @@ * @return array after pushes */ @SpecializedFunction - public static long push(final Object self, final Object arg) { + public static double push(final Object self, final Object arg) { try { final ScriptObject sobj = (ScriptObject)self; final ArrayData arrayData = sobj.getArray(); @@ -1498,7 +1483,7 @@ * @return index of element, or -1 if not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static long indexOf(final Object self, final Object searchElement, final Object fromIndex) { + public static double indexOf(final Object self, final Object searchElement, final Object fromIndex) { try { final ScriptObject sobj = (ScriptObject)Global.toObject(self); final long len = JSType.toUint32(sobj.getLength()); @@ -1534,7 +1519,7 @@ * @return index of element, or -1 if not found */ @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) - public static long lastIndexOf(final Object self, final Object... args) { + public static double lastIndexOf(final Object self, final Object... args) { try { final ScriptObject sobj = (ScriptObject)Global.toObject(self); final long len = JSType.toUint32(sobj.getLength()); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java Wed Jul 05 21:13:10 2017 +0200 @@ -168,9 +168,9 @@ } /** - * Wrap a native string in a NativeString object. + * Wrap a native boolean in a NativeBoolean object. * - * @param receiver Native string. + * @param receiver Native boolean. * @return Wrapped object. */ @SuppressWarnings("unused") diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java Wed Jul 05 21:13:10 2017 +0200 @@ -256,8 +256,9 @@ * @return a Date that points to the current moment in time */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) - public static long now(final Object self) { - return System.currentTimeMillis(); + public static double now(final Object self) { + // convert to double as long does not represent the primitive JS number type + return (double) System.currentTimeMillis(); } /** diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java Wed Jul 05 21:13:10 2017 +0200 @@ -48,6 +48,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion; +import jdk.nashorn.internal.runtime.linker.NashornGuards; import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; /** @@ -315,7 +316,7 @@ * @return Link to be invoked at call site. */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) { - return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER); + return PrimitiveLookup.lookupPrimitive(request, NashornGuards.getNumberGuard(), new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER); } @SuppressWarnings("unused") diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Wed Jul 05 21:13:10 2017 +0200 @@ -776,7 +776,7 @@ final MethodType getterType = MethodType.methodType(Object.class, clazz); final MethodType setterType = MethodType.methodType(Object.class, clazz, Object.class); - final GuardingDynamicLinker linker = BeansLinker.getLinkerForClass(clazz); + final GuardingDynamicLinker linker = Bootstrap.getBeanLinkerForClass(clazz); final List properties = new ArrayList<>(propertyNames.size() + methodNames.size()); for(final String methodName: methodNames) { diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Wed Jul 05 21:13:10 2017 +0200 @@ -74,7 +74,7 @@ @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE) public static Object length(final Object self) { if (self instanceof ScriptObject) { - return JSType.toUint32(((ScriptObject)self).getArray().length()); + return (double) JSType.toUint32(((ScriptObject)self).getArray().length()); } return 0; diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Wed Jul 05 21:13:10 2017 +0200 @@ -146,7 +146,7 @@ if (returnType == Object.class && JSType.isString(self)) { try { - return new GuardedInvocation(MH.findStatic(MethodHandles.lookup(), NativeString.class, "get", desc.getMethodType()), NashornGuards.getInstanceOf2Guard(String.class, ConsString.class)); + return new GuardedInvocation(MH.findStatic(MethodHandles.lookup(), NativeString.class, "get", desc.getMethodType()), NashornGuards.getStringGuard()); } catch (final LookupException e) { //empty. Shouldn't happen. Fall back to super } @@ -1235,8 +1235,8 @@ * @return Link to be invoked at call site. */ public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) { - final MethodHandle guard = NashornGuards.getInstanceOf2Guard(String.class, ConsString.class); - return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER); + return PrimitiveLookup.lookupPrimitive(request, NashornGuards.getStringGuard(), + new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER); } @SuppressWarnings("unused") diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java Wed Jul 05 21:13:10 2017 +0200 @@ -25,8 +25,14 @@ package jdk.nashorn.internal.objects; +import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import jdk.dynalink.linker.GuardedInvocation; +import jdk.dynalink.linker.LinkRequest; import jdk.nashorn.internal.WeakValueCache; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; @@ -39,6 +45,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.Symbol; import jdk.nashorn.internal.runtime.Undefined; +import jdk.nashorn.internal.runtime.linker.PrimitiveLookup; /** * ECMAScript 6 - 19.4 Symbol Objects @@ -48,12 +55,21 @@ private final Symbol symbol; + /** Method handle to create an object wrapper for a primitive symbol. */ + static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeSymbol.class, Object.class)); + /** Method handle to retrieve the Symbol prototype object. */ + private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class)); + // initialized by nasgen private static PropertyMap $nasgenmap$; /** See ES6 19.4.2.1 */ private static WeakValueCache globalSymbolRegistry = new WeakValueCache<>(); + NativeSymbol(final Symbol symbol) { + this(symbol, Global.instance()); + } + NativeSymbol(final Symbol symbol, final Global global) { this(symbol, global.getSymbolPrototype(), $nasgenmap$); } @@ -73,6 +89,17 @@ } } + /** + * Lookup the appropriate method for an invoke dynamic call. + * + * @param request The link request + * @param receiver The receiver for the call + * @return Link to be invoked at call site. + */ + public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) { + return PrimitiveLookup.lookupPrimitive(request, Symbol.class, new NativeSymbol((Symbol)receiver), WRAPFILTER, PROTOFILTER); + } + // ECMA 6 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint ) @Override public Object getDefaultValue(final Class typeHint) { @@ -149,4 +176,19 @@ final String name = ((Symbol) arg).getName(); return globalSymbolRegistry.get(name) == arg ? name : Undefined.getUndefined(); } + + @SuppressWarnings("unused") + private static NativeSymbol wrapFilter(final Object receiver) { + return new NativeSymbol((Symbol)receiver); + } + + @SuppressWarnings("unused") + private static Object protoFilter(final Object object) { + return Global.instance().getSymbolPrototype(); + } + + private static MethodHandle findOwnMH(final String name, final MethodType type) { + return MH.findStatic(MethodHandles.lookup(), NativeSymbol.class, name, type); + } + } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Wed Jul 05 21:13:10 2017 +0200 @@ -178,6 +178,12 @@ /** Method handle for void returns. */ public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class); + /** Method handle for isString method */ + public static final Call IS_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "isString", boolean.class, Object.class); + + /** Method handle for isNumber method */ + public static final Call IS_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "isNumber", boolean.class, Object.class); + /** * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide * in the dual--fields world @@ -280,7 +286,7 @@ return JSType.STRING; } - if (obj instanceof Number) { + if (isNumber(obj)) { return JSType.NUMBER; } @@ -322,7 +328,7 @@ return JSType.STRING; } - if (obj instanceof Number) { + if (isNumber(obj)) { return JSType.NUMBER; } @@ -434,7 +440,7 @@ return obj == null || obj == ScriptRuntime.UNDEFINED || isString(obj) || - obj instanceof Number || + isNumber(obj) || obj instanceof Boolean || obj instanceof Symbol; } @@ -610,6 +616,24 @@ } /** + * Returns true if object represents a primitive JavaScript number value. Note that we only + * treat wrapper objects of Java primitive number types as objects that can be fully represented + * as JavaScript numbers (doubles). This means we exclude {@code long} and special purpose Number + * instances such as {@link java.util.concurrent.atomic.AtomicInteger}, as well as arbitrary precision + * numbers such as {@link java.math.BigInteger}. + * + * @param obj the object + * @return true if the object represents a primitive JavaScript number value. + */ + public static boolean isNumber(final Object obj) { + if (obj != null) { + final Class c = obj.getClass(); + return c == Integer.class || c == Double.class || c == Float.class || c == Short.class || c == Byte.class; + } + return false; + } + + /** * JavaScript compliant conversion of integer to String * * @param num an integer @@ -761,7 +785,7 @@ if (obj instanceof Double) { return (Double)obj; } - if (obj instanceof Number) { + if (isNumber(obj)) { return ((Number)obj).doubleValue(); } return Double.NaN; @@ -1337,7 +1361,7 @@ return obj.toString(); } - if (obj instanceof Number) { + if (isNumber(obj)) { return toString(((Number)obj).doubleValue()); } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Wed Jul 05 21:13:10 2017 +0200 @@ -94,6 +94,9 @@ */ public static GuardedInvocation lookup(final CallSiteDescriptor desc) { final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc); + if (op == null) { + return null; + } switch (op) { case CALL: case NEW: diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Wed Jul 05 21:13:10 2017 +0200 @@ -287,7 +287,7 @@ * @param arg argument * @return new array length */ - public long fastPush(final int arg) { + public double fastPush(final int arg) { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } @@ -296,7 +296,7 @@ * @param arg argument * @return new array length */ - public long fastPush(final long arg) { + public double fastPush(final long arg) { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } @@ -305,7 +305,7 @@ * @param arg argument * @return new array length */ - public long fastPush(final double arg) { + public double fastPush(final double arg) { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } @@ -314,7 +314,7 @@ * @param arg argument * @return new array length */ - public long fastPush(final Object arg) { + public double fastPush(final Object arg) { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } @@ -330,14 +330,6 @@ * Specialization - fast pop implementation * @return element value */ - public long fastPopLong() { - throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink - } - - /** - * Specialization - fast pop implementation - * @return element value - */ public double fastPopDouble() { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Wed Jul 05 21:13:10 2017 +0200 @@ -340,7 +340,7 @@ } @Override - public long fastPush(final int arg) { + public double fastPush(final int arg) { final int len = (int)length(); if (len == array.length) { array = Arrays.copyOf(array, nextSize(len)); @@ -362,11 +362,6 @@ } @Override - public long fastPopLong() { - return fastPopInt(); - } - - @Override public double fastPopDouble() { return fastPopInt(); } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Wed Jul 05 21:13:10 2017 +0200 @@ -303,17 +303,17 @@ } @Override - public long fastPush(final int arg) { + public double fastPush(final int arg) { return fastPush((double)arg); } @Override - public long fastPush(final long arg) { + public double fastPush(final long arg) { return fastPush((double)arg); } @Override - public long fastPush(final double arg) { + public double fastPush(final double arg) { final int len = (int)length(); if (len == array.length) { //note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Wed Jul 05 21:13:10 2017 +0200 @@ -236,22 +236,22 @@ } @Override - public long fastPush(final int arg) { + public double fastPush(final int arg) { return fastPush((Object)arg); } @Override - public long fastPush(final long arg) { + public double fastPush(final long arg) { return fastPush((Object)arg); } @Override - public long fastPush(final double arg) { + public double fastPush(final double arg) { return fastPush((Object)arg); } @Override - public long fastPush(final Object arg) { + public double fastPush(final Object arg) { final int len = (int)length(); if (len == array.length) { array = Arrays.copyOf(array, nextSize(len)); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Jul 05 21:13:10 2017 +0200 @@ -40,10 +40,11 @@ import jdk.dynalink.beans.BeansLinker; import jdk.dynalink.beans.StaticClass; import jdk.dynalink.linker.GuardedInvocation; -import jdk.dynalink.linker.GuardedInvocationTransformer; +import jdk.dynalink.linker.GuardingDynamicLinker; import jdk.dynalink.linker.LinkRequest; import jdk.dynalink.linker.LinkerServices; import jdk.dynalink.linker.MethodTypeConversionStrategy; +import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.dynalink.linker.support.TypeUtilities; import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.codegen.CompilerConstants.Call; @@ -67,6 +68,24 @@ private static final MethodHandle VOID_TO_OBJECT = MH.constant(Object.class, ScriptRuntime.UNDEFINED); + private static final BeansLinker beansLinker = new BeansLinker(Bootstrap::createMissingMemberHandler); + private static final GuardingDynamicLinker[] prioritizedLinkers; + private static final GuardingDynamicLinker[] fallbackLinkers; + static { + final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker(beansLinker); + prioritizedLinkers = new GuardingDynamicLinker[] { + new NashornLinker(), + new NashornPrimitiveLinker(), + new NashornStaticClassLinker(beansLinker), + new BoundCallableLinker(), + new JavaSuperAdapterLinker(beansLinker), + new JSObjectLinker(nashornBeansLinker), + new BrowserJSObjectLinker(nashornBeansLinker), + new ReflectionCheckLinker() + }; + fallbackLinkers = new GuardingDynamicLinker[] {nashornBeansLinker, new NashornBottomLinker() }; + } + // do not create me!! private Bootstrap() { } @@ -81,31 +100,14 @@ public static DynamicLinker createDynamicLinker(final ClassLoader appLoader, final int unstableRelinkThreshold) { final DynamicLinkerFactory factory = new DynamicLinkerFactory(); - final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker(); - factory.setPrioritizedLinkers( - new NashornLinker(), - new NashornPrimitiveLinker(), - new NashornStaticClassLinker(), - new BoundCallableLinker(), - new JavaSuperAdapterLinker(), - new JSObjectLinker(nashornBeansLinker), - new BrowserJSObjectLinker(nashornBeansLinker), - new ReflectionCheckLinker()); - factory.setFallbackLinkers(nashornBeansLinker, new NashornBottomLinker()); + factory.setPrioritizedLinkers(prioritizedLinkers); + factory.setFallbackLinkers(fallbackLinkers); factory.setSyncOnRelink(true); - factory.setPrelinkTransformer(new GuardedInvocationTransformer() { - @Override - public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) { - final CallSiteDescriptor desc = request.getCallSiteDescriptor(); - return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType()); - } + factory.setPrelinkTransformer((inv, request, linkerServices) -> { + final CallSiteDescriptor desc = request.getCallSiteDescriptor(); + return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType()); }); - factory.setAutoConversionStrategy(new MethodTypeConversionStrategy() { - @Override - public MethodHandle asType(final MethodHandle target, final MethodType newType) { - return unboxReturnType(target, newType); - } - }); + factory.setAutoConversionStrategy(Bootstrap::unboxReturnType); factory.setInternalObjectsFilter(NashornBeansLinker.createHiddenObjectFilter()); factory.setUnstableRelinkThreshold(unstableRelinkThreshold); @@ -115,6 +117,15 @@ } /** + * Returns a dynamic linker for the specific Java class using beans semantics. + * @param clazz the Java class + * @return a dynamic linker for the specific Java class using beans semantics. + */ + public static TypeBasedGuardingDynamicLinker getBeanLinkerForClass(final Class clazz) { + return beansLinker.getLinkerForClass(clazz); + } + + /** * Returns if the given object is a "callable" * @param obj object to be checked for callability * @return true if the obj is callable @@ -475,4 +486,14 @@ } return target; } + + private static MethodHandle createMissingMemberHandler( + final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + if (BrowserJSObjectLinker.canLinkTypeStatic(linkRequest.getReceiver().getClass())) { + // Don't create missing member handlers for the browser JS objects as they + // have their own logic. + return null; + } + return NashornBottomLinker.linkMissingBeanMember(linkRequest, linkerServices); + } } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -25,7 +25,6 @@ package jdk.nashorn.internal.runtime.linker; -import static jdk.nashorn.internal.lookup.Lookup.EMPTY_GETTER; import static jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.SUPER_PREFIX; import java.lang.invoke.MethodHandle; @@ -62,6 +61,12 @@ IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class); } + private final BeansLinker beansLinker; + + JavaSuperAdapterLinker(final BeansLinker beansLinker) { + this.beansLinker = beansLinker; + } + @Override public boolean canLinkType(final Class type) { return type == JavaSuperAdapter.class; @@ -101,17 +106,13 @@ // Delegate to BeansLinker final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation( - BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args), + beansLinker, linkRequest.replaceArguments(newDescriptor, args), linkerServices); + // Even for non-existent methods, Bootstrap's BeansLinker will link a + // noSuchMember handler. + assert guardedInv != null; final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass); - if(guardedInv == null) { - // Short circuit the lookup here for non-existent methods by linking an empty getter. If we just returned - // null instead, BeansLinker would find final methods on the JavaSuperAdapter instead: getClass() and - // wait(). - return new GuardedInvocation(MethodHandles.dropArguments(EMPTY_GETTER, 1,type.parameterList().subList(1, - type.parameterCount())), guard).asType(descriptor); - } final MethodHandle invocation = guardedInv.getInvocation(); final MethodType invType = invocation.type(); @@ -165,7 +166,7 @@ */ @SuppressWarnings("unused") private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) { - return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null); + return dynamicMethod == ScriptRuntime.UNDEFINED ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null); } /** diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -85,7 +85,11 @@ } }; - private final BeansLinker beansLinker = new BeansLinker(); + private final BeansLinker beansLinker; + + NashornBeansLinker(final BeansLinker beansLinker) { + this.beansLinker = beansLinker; + } @Override public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -27,26 +27,27 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; -import static jdk.nashorn.internal.runtime.JSType.GET_UNDEFINED; -import static jdk.nashorn.internal.runtime.JSType.TYPE_OBJECT_INDEX; import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; import jdk.dynalink.CallSiteDescriptor; import jdk.dynalink.NamedOperation; import jdk.dynalink.Operation; +import jdk.dynalink.StandardOperation; import jdk.dynalink.beans.BeansLinker; import jdk.dynalink.linker.GuardedInvocation; import jdk.dynalink.linker.GuardingDynamicLinker; import jdk.dynalink.linker.GuardingTypeConverterFactory; import jdk.dynalink.linker.LinkRequest; import jdk.dynalink.linker.LinkerServices; -import jdk.dynalink.linker.support.Guards; +import jdk.dynalink.linker.support.Lookup; import jdk.nashorn.internal.codegen.types.Type; +import jdk.nashorn.internal.runtime.ECMAException; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.UnwarrantedOptimismException; @@ -73,7 +74,7 @@ // this point is a generic Java bean. Therefore, reaching here with a ScriptObject is a Nashorn bug. assert isExpectedObject(self) : "Couldn't link " + linkRequest.getCallSiteDescriptor() + " for " + self.getClass().getName(); - return linkBean(linkRequest, linkerServices); + return linkBean(linkRequest); } private static final MethodHandle EMPTY_PROP_GETTER = @@ -85,7 +86,18 @@ private static final MethodHandle EMPTY_ELEM_SETTER = MH.dropArguments(EMPTY_PROP_SETTER, 0, Object.class); - private static GuardedInvocation linkBean(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + private static final MethodHandle THROW_NO_SUCH_FUNCTION; + private static final MethodHandle THROW_STRICT_PROPERTY_SETTER; + private static final MethodHandle THROW_OPTIMISTIC_UNDEFINED; + + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); + THROW_NO_SUCH_FUNCTION = lookup.findOwnStatic("throwNoSuchFunction", Object.class, Object.class, Object.class); + THROW_STRICT_PROPERTY_SETTER = lookup.findOwnStatic("throwStrictPropertySetter", void.class, Object.class, Object.class); + THROW_OPTIMISTIC_UNDEFINED = lookup.findOwnStatic("throwOptimisticUndefined", Object.class, int.class); + } + + private static GuardedInvocation linkBean(final LinkRequest linkRequest) throws Exception { final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); final Object self = linkRequest.getReceiver(); switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) { @@ -105,35 +117,79 @@ throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self)); } throw typeError("not.a.function", NashornCallSiteDescriptor.getFunctionErrorMessage(desc, self)); - case CALL_METHOD: - throw typeError("no.such.function", getArgument(linkRequest), ScriptRuntime.safeToString(self)); - case GET_METHOD: - // evaluate to undefined, later on Undefined will take care of throwing TypeError - return getInvocation(MH.dropArguments(GET_UNDEFINED.get(TYPE_OBJECT_INDEX), 0, Object.class), self, linkerServices, desc); - case GET_PROPERTY: - case GET_ELEMENT: - if(NashornCallSiteDescriptor.isOptimistic(desc)) { - throw new UnwarrantedOptimismException(UNDEFINED, NashornCallSiteDescriptor.getProgramPoint(desc), Type.OBJECT); - } - if (NashornCallSiteDescriptor.getOperand(desc) != null) { - return getInvocation(EMPTY_PROP_GETTER, self, linkerServices, desc); - } - return getInvocation(EMPTY_ELEM_GETTER, self, linkerServices, desc); - case SET_PROPERTY: - case SET_ELEMENT: - final boolean strict = NashornCallSiteDescriptor.isStrict(desc); - if (strict) { - throw typeError("cant.set.property", getArgument(linkRequest), ScriptRuntime.safeToString(self)); - } - if (NashornCallSiteDescriptor.getOperand(desc) != null) { - return getInvocation(EMPTY_PROP_SETTER, self, linkerServices, desc); - } - return getInvocation(EMPTY_ELEM_SETTER, self, linkerServices, desc); default: + // Everything else is supposed to have been already handled by Bootstrap.beansLinker + // delegating to linkNoSuchBeanMember throw new AssertionError("unknown call type " + desc); } } + static MethodHandle linkMissingBeanMember(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { + final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor(); + final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc); + if (op != null) { + final String operand = NashornCallSiteDescriptor.getOperand(desc); + switch (op) { + case CALL_METHOD: + return adaptThrower(bindOperand(THROW_NO_SUCH_FUNCTION, operand), desc); + case GET_METHOD: + case GET_PROPERTY: + case GET_ELEMENT: { + if (NashornCallSiteDescriptor.isOptimistic(desc)) { + return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc); + } + if (NashornCallSiteDescriptor.getOperand(desc) != null) { + return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc); + } + return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc); + } + case SET_PROPERTY: + case SET_ELEMENT: + final boolean strict = NashornCallSiteDescriptor.isStrict(desc); + if (strict) { + return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc); + } + if (NashornCallSiteDescriptor.getOperand(desc) != null) { + return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc); + } + return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc); + default: + } + } + throw new AssertionError("unknown call type " + desc); + } + + private static MethodHandle bindOperand(final MethodHandle handle, final String operand) { + return operand == null ? handle : MethodHandles.insertArguments(handle, 1, operand); + } + + private static MethodHandle adaptThrower(final MethodHandle handle, final CallSiteDescriptor desc) { + final MethodType targetType = desc.getMethodType(); + final int paramCount = handle.type().parameterCount(); + return MethodHandles + .dropArguments(handle, paramCount, targetType.parameterList().subList(paramCount, targetType.parameterCount())) + .asType(targetType); + } + + @SuppressWarnings("unused") + private static Object throwNoSuchFunction(final Object self, final Object name) { + throw createTypeError(self, name, "no.such.function"); + } + + @SuppressWarnings("unused") + private static void throwStrictPropertySetter(final Object self, final Object name) { + throw createTypeError(self, name, "cant.set.property"); + } + + private static ECMAException createTypeError(final Object self, final Object name, final String msg) { + return typeError(msg, String.valueOf(name), ScriptRuntime.safeToString(self)); + } + + @SuppressWarnings("unused") + private static Object throwOptimisticUndefined(final int programPoint) { + throw new UnwarrantedOptimismException(UNDEFINED, programPoint, Type.OBJECT); + } + @Override public GuardedInvocation convertToType(final Class sourceType, final Class targetType, final Supplier lookupSupplier) throws Exception { final GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType); @@ -158,8 +214,8 @@ return null; } - private static GuardedInvocation getInvocation(final MethodHandle handle, final Object self, final LinkerServices linkerServices, final CallSiteDescriptor desc) { - return Bootstrap.asTypeSafeReturn(new GuardedInvocation(handle, Guards.getClassGuard(self.getClass())), linkerServices, desc); + private static MethodHandle getInvocation(final MethodHandle handle, final LinkerServices linkerServices, final CallSiteDescriptor desc) { + return linkerServices.asTypeLosslessReturn(handle, desc.getMethodType()); } // Used solely in an assertion to figure out if the object we get here is something we in fact expect. Objects diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornGuards.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornGuards.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornGuards.java Wed Jul 05 21:13:10 2017 +0200 @@ -34,6 +34,7 @@ import jdk.dynalink.linker.LinkRequest; import jdk.nashorn.api.scripting.JSObject; import jdk.nashorn.internal.objects.Global; +import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; @@ -46,10 +47,9 @@ public final class NashornGuards { private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, ScriptObject.class, PropertyMap.class); private static final MethodHandle IS_MAP_SCRIPTOBJECT = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class); - private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class); private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class); private static final MethodHandle IS_NOT_JSOBJECT = findOwnMH("isNotJSObject", boolean.class, Object.class); - private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class); + private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class); //TODO - maybe put this back in ScriptFunction instead of the ClassCastException.class relinkage //private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class); @@ -165,14 +165,21 @@ } /** - * Get a guard that checks if in item is an instance of either of two classes. + * Get a guard that checks if in item is a JS string. * - * @param class1 the first class - * @param class2 the second class * @return method handle for guard */ - public static MethodHandle getInstanceOf2Guard(final Class class1, final Class class2) { - return MH.insertArguments(IS_INSTANCEOF_2, 1, class1, class2); + public static MethodHandle getStringGuard() { + return JSType.IS_STRING.methodHandle(); + } + + /** + * Get a guard that checks if in item is a JS number. + * + * @return method handle for guard + */ + public static MethodHandle getNumberGuard() { + return JSType.IS_NUMBER.methodHandle(); } /** @@ -224,11 +231,6 @@ } @SuppressWarnings("unused") - private static boolean isInstanceOf2(final Object self, final Class class1, final Class class2) { - return class1.isInstance(self) || class2.isInstance(self); - } - - @SuppressWarnings("unused") private static boolean isScriptFunction(final Object self) { return self instanceof ScriptFunction; } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -41,6 +41,7 @@ import jdk.nashorn.internal.runtime.ConsString; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.Symbol; /** * Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other @@ -57,7 +58,9 @@ } private static boolean canLinkTypeStatic(final Class type) { - return type == String.class || type == Boolean.class || type == ConsString.class || Number.class.isAssignableFrom(type); + return type == String.class || type == Boolean.class || type == ConsString.class || type == Integer.class + || type == Double.class || type == Float.class || type == Short.class || type == Byte.class + || type == Symbol.class; } @Override @@ -167,7 +170,7 @@ @SuppressWarnings("unused") private static boolean isJavaScriptPrimitive(final Object o) { - return JSType.isString(o) || o instanceof Boolean || o instanceof Number || o == null; + return JSType.isString(o) || o instanceof Boolean || JSType.isNumber(o) || o == null || o instanceof Symbol; } private static final MethodHandle GUARD_PRIMITIVE = findOwnMH("isJavaScriptPrimitive", boolean.class, Object.class); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Wed Jul 05 21:13:10 2017 +0200 @@ -53,7 +53,11 @@ * */ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker { - private static final GuardingDynamicLinker staticClassLinker = BeansLinker.getLinkerForClass(StaticClass.class); + private final GuardingDynamicLinker staticClassLinker; + + NashornStaticClassLinker(final BeansLinker beansLinker) { + this.staticClassLinker = beansLinker.getLinkerForClass(StaticClass.class); + } @Override public boolean canLinkType(final Class type) { @@ -100,7 +104,7 @@ return delegate(linkerServices, request); } - private static GuardedInvocation delegate(final LinkerServices linkerServices, final LinkRequest request) throws Exception { + private GuardedInvocation delegate(final LinkerServices linkerServices, final LinkRequest request) throws Exception { return NashornBeansLinker.getGuardedInvocation(staticClassLinker, request, linkerServices); } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/JDK-8030200.js --- a/nashorn/test/script/basic/JDK-8030200.js Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8030200.js Wed Jul 05 21:13:10 2017 +0200 @@ -33,4 +33,4 @@ var s = n.toString(5); var m = parseInt(s, 5); print(m === n); -print(n); +print(m); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/JDK-8049242.js.EXPECTED --- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED Wed Jul 05 21:13:10 2017 +0200 @@ -1,10 +1,10 @@ abc [jdk.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] ava -TypeError: null is not a function -TypeError: null is not a function -TypeError: null is not a function +TypeError: Java.type("java.lang.Object")["()xxxxx"] is not a function +TypeError: Java.type("java.lang.Object")["("] is not a function +TypeError: Java.type("java.lang.Object")[")"] is not a function TypeError: Constructor [jdk.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new". -TypeError: null is not a function -TypeError: null is not a function +TypeError: Java.type("java.lang.Runnable")["()"] is not a function +TypeError: Java.type("java.lang.Runnable")["(int)"] is not a function java.lang.InstantiationException: java.io.InputStream diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/JDK-8066669.js --- a/nashorn/test/script/basic/JDK-8066669.js Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8066669.js Wed Jul 05 21:13:10 2017 +0200 @@ -29,12 +29,13 @@ */ // Make sure index access on Java objects is working as expected. -var map = new java.util.HashMap(); +var map = new java.util.LinkedHashMap(); map["foo"] = "bar"; map[1] = 2; map[false] = true; map[null] = 0; +map["a"] = null; print(map); @@ -49,10 +50,12 @@ print(typeof map[1], map[1]); print(typeof map[false], map[false]); print(typeof map[null], map[null]); +print(typeof map["a"], map["a"]); -print(map.foo); -print(map.false); -print(map.null); +print("map.foo=" + map.foo); +print("map.false=" + map.false); +print("map.null=" + map.null); +print("map.a=" + map.a); map.foo = "baz"; print(map); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/JDK-8066669.js.EXPECTED --- a/nashorn/test/script/basic/JDK-8066669.js.EXPECTED Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8066669.js.EXPECTED Wed Jul 05 21:13:10 2017 +0200 @@ -1,13 +1,16 @@ -{null=0, 1=2, false=true, foo=bar} -object null +{foo=bar, 1=2, false=true, null=0, a=null} +string foo number 1 boolean false -string foo +object null +string a string bar number 2 boolean true number 0 -bar -null -null -{null=0, 1=2, false=true, foo=baz} +object null +map.foo=bar +map.false=undefined +map.null=undefined +map.a=null +{foo=baz, 1=2, false=true, null=0, a=null} diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/JDK-8079145.js.EXPECTED --- a/nashorn/test/script/basic/JDK-8079145.js.EXPECTED Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/JDK-8079145.js.EXPECTED Wed Jul 05 21:13:10 2017 +0200 @@ -5,8 +5,8 @@ int array: check widen for true [class java.lang.Boolean] int array: check widen for 34 [class java.lang.Byte] int array: check widen for 344454 [class java.lang.Integer] -int array: check widen for 454545 [class java.lang.Long] -int array: check widen for 2147483648 [class java.lang.Long] +int array: check widen for 454545 +int array: check widen for 2147483648 int array: check widen for 34.29999923706055 [class java.lang.Float] int array: check widen for 3.141592653589793 [class java.lang.Double] int array: check widen for s @@ -17,8 +17,8 @@ long array: check widen for true [class java.lang.Boolean] long array: check widen for 34 [class java.lang.Byte] long array: check widen for 344454 [class java.lang.Integer] -long array: check widen for 454545 [class java.lang.Long] -long array: check widen for 2147483648 [class java.lang.Long] +long array: check widen for 454545 +long array: check widen for 2147483648 long array: check widen for 34.29999923706055 [class java.lang.Float] long array: check widen for 3.141592653589793 [class java.lang.Double] long array: check widen for s @@ -29,8 +29,8 @@ number array: check widen for true [class java.lang.Boolean] number array: check widen for 34 [class java.lang.Byte] number array: check widen for 344454 [class java.lang.Integer] -number array: check widen for 454545 [class java.lang.Long] -number array: check widen for 2147483648 [class java.lang.Long] +number array: check widen for 454545 +number array: check widen for 2147483648 number array: check widen for 34.29999923706055 [class java.lang.Float] number array: check widen for 3.141592653589793 [class java.lang.Double] number array: check widen for s @@ -41,8 +41,8 @@ object array: check widen for true [class java.lang.Boolean] object array: check widen for 34 [class java.lang.Byte] object array: check widen for 344454 [class java.lang.Integer] -object array: check widen for 454545 [class java.lang.Long] -object array: check widen for 2147483648 [class java.lang.Long] +object array: check widen for 454545 +object array: check widen for 2147483648 object array: check widen for 34.29999923706055 [class java.lang.Float] object array: check widen for 3.141592653589793 [class java.lang.Double] object array: check widen for s diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/JDK-8143896.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/basic/JDK-8143896.js Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/** + * JDK-8143896: java.lang.Long is implicitly converted to double + * + * @test + * @run + */ + +Assert.assertTrue(java.lang.Long.valueOf("301077366599181567").toString() === "301077366599181567"); +Assert.assertTrue(java.lang.Long.valueOf("-301077366599181567").toString() === "-301077366599181567"); +Assert.assertTrue(java.lang.Long.valueOf("301077366599181567") == 301077366599181567); +Assert.assertFalse(java.lang.Long.valueOf("301077366599181567") === 301077366599181567); + +Assert.assertTrue(new java.math.BigInteger("301077366599181567").toString() === "301077366599181567"); +Assert.assertTrue(new java.math.BigInteger("-301077366599181567").toString() === "-301077366599181567"); +Assert.assertTrue(new java.math.BigInteger("301077366599181567") == 301077366599181567); +Assert.assertFalse(new java.math.BigInteger("301077366599181567") === 301077366599181567); + + +var n = new java.lang.Byte("123"); +Assert.assertTrue(typeof n === "number"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertTrue(n === 123); + +n = new java.lang.Short("123"); +Assert.assertTrue(typeof n === "number"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertTrue(n === 123); + +n = new java.lang.Integer("123"); +Assert.assertTrue(typeof n === "number"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertTrue(n === 123); + +n = new java.lang.Float("123"); +Assert.assertTrue(typeof n === "number"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertTrue(n === 123); + +n = new java.lang.Double("123"); +Assert.assertTrue(typeof n === "number"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertTrue(n === 123); + +n = new java.lang.Long("123"); +Assert.assertTrue(typeof n === "object"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertFalse(n === 123); + +n = new java.util.concurrent.atomic.DoubleAdder(); +n.add("123"); +Assert.assertTrue(typeof n === "object"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertFalse(n === 123); + +n = new java.util.concurrent.atomic.AtomicInteger(123); +Assert.assertTrue(typeof n === "object"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertFalse(n === 123); + +n = new java.util.concurrent.atomic.AtomicLong(123); +Assert.assertTrue(typeof n === "object"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertFalse(n === 123); + +n = new java.math.BigInteger("123"); +Assert.assertTrue(typeof n === "object"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertFalse(n === 123); + +n = new java.math.BigDecimal("123"); +Assert.assertTrue(typeof n === "object"); +Assert.assertTrue(n + 1 === 124); +Assert.assertTrue(n == 123); +Assert.assertFalse(n === 123); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/es6/symbols.js --- a/nashorn/test/script/basic/es6/symbols.js Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/es6/symbols.js Wed Jul 05 21:13:10 2017 +0200 @@ -40,11 +40,11 @@ Assert.assertTrue(Symbol(null).toString() === 'Symbol(null)'); Assert.assertTrue(Symbol(undefined).toString() === 'Symbol()'); -var s1 = Symbol(); -var s2 = Symbol("s2"); +const s1 = Symbol(); +const s2 = Symbol("s2"); Assert.assertFalse(s1 instanceof Symbol); // not an object -var obj = {}; +let obj = {}; obj['foo'] = 'foo'; obj[s1] = s1; obj['bar'] = 'bar'; @@ -57,17 +57,17 @@ Assert.assertTrue(obj[1] === 1); Assert.assertTrue(obj[s2] === s2); -var expectedNames = ['1', 'foo', 'bar']; -var expectedSymbols = [s1, s2]; -var actualNames = Object.getOwnPropertyNames(obj); -var actualSymbols = Object.getOwnPropertySymbols(obj); +const expectedNames = ['1', 'foo', 'bar']; +const expectedSymbols = [s1, s2]; +const actualNames = Object.getOwnPropertyNames(obj); +let actualSymbols = Object.getOwnPropertySymbols(obj); Assert.assertTrue(expectedNames.length == actualNames.length); Assert.assertTrue(expectedSymbols.length == actualSymbols.length); -for (var key in expectedNames) { +for (let key in expectedNames) { Assert.assertTrue(expectedNames[key] === actualNames[key]); } -for (var key in expectedSymbols) { +for (let key in expectedSymbols) { Assert.assertTrue(expectedSymbols[key] === actualSymbols[key]); } @@ -114,8 +114,8 @@ // Symbol.for and Symbol.keyFor -var uncached = Symbol('foo'); -var cached = Symbol.for('foo'); +const uncached = Symbol('foo'); +const cached = Symbol.for('foo'); Assert.assertTrue(uncached !== cached); Assert.assertTrue(Symbol.keyFor(uncached) === undefined); @@ -123,9 +123,15 @@ Assert.assertTrue(cached === Symbol.for('foo')); Assert.assertTrue(cached === Symbol.for('f' + 'oo')); +// JDK-8147008: Make sure symbols are handled by primitive linker +Symbol.prototype.foo = 123; +Symbol.prototype[s2] = s2; +Assert.assertEquals(s1.foo, 123); +Assert.assertEquals(s2[s2], s2); + // Object wrapper -var o = Object(s1); +const o = Object(s1); obj = {}; obj[s1] = "s1"; Assert.assertTrue(o == s1); @@ -134,6 +140,8 @@ Assert.assertTrue(o instanceof Symbol); Assert.assertTrue(obj[o] == 's1'); Assert.assertTrue(o in obj); +Assert.assertEquals(o.foo, 123); +Assert.assertEquals(o[s2], s2); // various non-strict comparisons that should fail diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/list.js --- a/nashorn/test/script/basic/list.js Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/list.js Wed Jul 05 21:13:10 2017 +0200 @@ -54,15 +54,14 @@ var size_name = "size" print("l[size_name]()=" + l[size_name]()) // ... but existing methods can be accessed with [] -expectException(2) // Java lists don't auto-expand to accommodate new indices -expectException(java.lang.Double.POSITIVE_INFINITY) // Dynalink will throw IOOBE -expectException(java.lang.Double.NEGATIVE_INFINITY) // Dynalink will throw IOOBE +// All illegal indices, even those out of bounds, return undefined +print("l[2]=" + l[2]); +print("l[-1]=" + l[-1]); +print("l[2.1]=" + l[2.1]); +print("l[-1.1]=" + l[-1.1]); +print("l[Infinity]=" + l[Infinity]); +print("l[-Infinity]=" + l[-Infinity]); +print("l[NaN]=" + l[NaN]); -function expectException(index) { - try { - l[index] = "x" - print("Not caught out-of-bounds assignment for " + index) - } catch(e) { - print(e) - } -} +l[1.1]="b"; // should be no-op +print("l[0]=" + l[0]); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/list.js.EXPECTED --- a/nashorn/test/script/basic/list.js.EXPECTED Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/list.js.EXPECTED Wed Jul 05 21:13:10 2017 +0200 @@ -9,9 +9,14 @@ --for each end-- l[0]=foo l[1]=a -l[0.9]=null +l[0.9]=undefined l['blah']=undefined l[size_name]()=2 -java.lang.IndexOutOfBoundsException: Index: 2, Size: 2 -java.lang.IndexOutOfBoundsException: Index: Infinity, Size: 2 -java.lang.IndexOutOfBoundsException: Index: -Infinity, Size: 2 +l[2]=undefined +l[-1]=undefined +l[2.1]=undefined +l[-1.1]=undefined +l[Infinity]=undefined +l[-Infinity]=undefined +l[NaN]=undefined +l[0]=foo diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/map.js --- a/nashorn/test/script/basic/map.js Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/map.js Wed Jul 05 21:13:10 2017 +0200 @@ -44,8 +44,8 @@ print("m['empty'] = " + m['empty']) print("m[empty_key] = " + m[empty_key]) // prints "foo" -print("m.bwah = " + m.bwah) // prints "null" -print("m['bwah'] = " + m['bwah']) // prints "null" +print("m.bwah = " + m.bwah) // prints "undefined" +print("m['bwah'] = " + m['bwah']) // prints "undefined" m.put("twonk", "ding") print("m.twonk = " + m.twonk) // prints "ding" diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/basic/map.js.EXPECTED --- a/nashorn/test/script/basic/map.js.EXPECTED Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/script/basic/map.js.EXPECTED Wed Jul 05 21:13:10 2017 +0200 @@ -7,8 +7,8 @@ m.empty = false m['empty'] = foo m[empty_key] = foo -m.bwah = null -m['bwah'] = null +m.bwah = undefined +m['bwah'] = undefined m.twonk = ding m['twonk'] = ding m.size()=2 diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/script/nosecurity/context-dependent-logging.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/test/script/nosecurity/context-dependent-logging.js Wed Jul 05 21:13:10 2017 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Test that logging configuration is per engine, rather than per process. + * + * @test + * @bug 8036977 + * @run/ignore-std-error + * @fork + * @option -scripting + */ + +// To test, start another engine (testEngine) with a time logger and ensure the +// logger exists. + +var NashornFactory = new (Java.type('jdk.nashorn.api.scripting.NashornScriptEngineFactory'))(), + testEngine = NashornFactory.getScriptEngine("-scripting", "--log=time") + +if (!testEngine.eval('$OPTIONS._loggers.time')) { + throw 'fresh testEngine does not have time logger' +} + +// To test further, have the testEngine start yet another engine (e) without +// time logging, but with compiler logging. Check the logging is as configured, +// and verify the testEngine still has time logging, but no compiler logging. + +var script = < { + // This is a MissingMemberHandlerFactory that creates a missing + // member handler for element getters and setters that throw an + // ArrayIndexOutOfBoundsException when applied to an array and an + // IndexOutOfBoundsException when applied to a list. + + final CallSiteDescriptor desc = req.getCallSiteDescriptor(); + final Operation op = desc.getOperation(); + final Operation baseOp = NamedOperation.getBaseOperation(op); + if (baseOp != GET_ELEMENT && baseOp != SET_ELEMENT) { + // We only handle GET_ELEMENT and SET_ELEMENT. + return null; + } + + final Object receiver = req.getReceiver(); + Assert.assertNotNull(receiver); + + final Class clazz = receiver.getClass(); + final MethodHandle throwerHandle; + if (clazz.isArray()) { + throwerHandle = throwArrayIndexOutOfBounds; + } else if (List.class.isAssignableFrom(clazz)) { + throwerHandle = throwIndexOutOfBounds; + } else { + Assert.fail("Unexpected receiver type " + clazz.getName()); + return null; + } + + final Object name = NamedOperation.getName(op); + final MethodHandle nameBoundHandle; + if (name == null) { + nameBoundHandle = throwerHandle; + } else { + // If the operation is for a fixed index, bind it + nameBoundHandle = MethodHandles.insertArguments(throwerHandle, 1, name); + } + + final MethodType callSiteType = desc.getMethodType(); + final MethodHandle arityMatchedHandle; + if (baseOp == SET_ELEMENT) { + // Drop "value" parameter for a setter + final int handleArity = nameBoundHandle.type().parameterCount(); + arityMatchedHandle = MethodHandles.dropArguments(nameBoundHandle, + handleArity, callSiteType.parameterType(handleArity)); + } else { + arityMatchedHandle = nameBoundHandle; + } + + return arityMatchedHandle.asType(callSiteType); + })); this.linker = factory.createLinker(); } @@ -86,7 +166,7 @@ @Test(dataProvider = "flags") public void getPropertyTest(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, mt); + final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class); Assert.assertEquals(cs.getTarget().invoke(new Date(), "class"), Date.class); } @@ -94,14 +174,14 @@ @Test(dataProvider = "flags") public void getPropertyNegativeTest(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, mt); + final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); Assert.assertNull(cs.getTarget().invoke(new Object(), "DOES_NOT_EXIST")); } @Test(dataProvider = "flags") public void getPropertyTest2(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(Object.class, Object.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, "class", mt); + final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "class", mt); Assert.assertEquals(cs.getTarget().invoke(new Object()), Object.class); Assert.assertEquals(cs.getTarget().invoke(new Date()), Date.class); } @@ -109,12 +189,12 @@ @Test(dataProvider = "flags") public void getPropertyNegativeTest2(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(Object.class, Object.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, "DOES_NOT_EXIST", mt); + final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "DOES_NOT_EXIST", mt); try { cs.getTarget().invoke(new Object()); throw new RuntimeException("Expected NoSuchDynamicMethodException"); - } catch (Throwable th) { + } catch (final Throwable th) { Assert.assertTrue(th instanceof NoSuchDynamicMethodException); } } @@ -122,7 +202,7 @@ @Test(dataProvider = "flags") public void getLengthPropertyTest(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(int.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, mt); + final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt); Assert.assertEquals((int) cs.getTarget().invoke(new int[10], "length"), 10); Assert.assertEquals((int) cs.getTarget().invoke(new String[33], "length"), 33); @@ -131,7 +211,7 @@ @Test(dataProvider = "flags") public void getlengthTest(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(int.class, Object.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_LENGTH, mt); + final CallSite cs = createCallSite(publicLookup, GET_LENGTH, mt); final int[] arr = {23, 42}; Assert.assertEquals((int) cs.getTarget().invoke((Object) arr), 2); @@ -151,21 +231,21 @@ @Test(dataProvider = "flags") public void getElementTest(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(int.class, Object.class, int.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_ELEMENT, mt); + final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt); final int[] arr = {23, 42}; Assert.assertEquals((int) cs.getTarget().invoke(arr, 0), 23); Assert.assertEquals((int) cs.getTarget().invoke(arr, 1), 42); try { - int x = (int) cs.getTarget().invoke(arr, -1); + final int x = (int) cs.getTarget().invoke(arr, -1); throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); - } catch (ArrayIndexOutOfBoundsException ex) { + } catch (final ArrayIndexOutOfBoundsException ex) { } try { - int x = (int) cs.getTarget().invoke(arr, arr.length); + final int x = (int) cs.getTarget().invoke(arr, arr.length); throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); - } catch (ArrayIndexOutOfBoundsException ex) { + } catch (final ArrayIndexOutOfBoundsException ex) { } final List list = new ArrayList<>(); @@ -176,22 +256,22 @@ Assert.assertEquals((int) cs.getTarget().invoke(list, 1), (int) list.get(1)); Assert.assertEquals((int) cs.getTarget().invoke(list, 2), (int) list.get(2)); try { - int x = (int) cs.getTarget().invoke(list, -1); + final int x = (int) cs.getTarget().invoke(list, -1); throw new RuntimeException("expected IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException ex) { + } catch (final IndexOutOfBoundsException ex) { } try { - int x = (int) cs.getTarget().invoke(list, list.size()); + final int x = (int) cs.getTarget().invoke(list, list.size()); throw new RuntimeException("expected IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException ex) { + } catch (final IndexOutOfBoundsException ex) { } } @Test(dataProvider = "flags") public void setElementTest(final boolean publicLookup) throws Throwable { final MethodType mt = MethodType.methodType(void.class, Object.class, int.class, int.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.SET_ELEMENT, mt); + final CallSite cs = createCallSite(publicLookup, SET_ELEMENT, mt); final int[] arr = {23, 42}; cs.getTarget().invoke(arr, 0, 0); @@ -202,13 +282,13 @@ try { cs.getTarget().invoke(arr, -1, 12); throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); - } catch (ArrayIndexOutOfBoundsException ex) { + } catch (final ArrayIndexOutOfBoundsException ex) { } try { cs.getTarget().invoke(arr, arr.length, 20); throw new RuntimeException("expected ArrayIndexOutOfBoundsException"); - } catch (ArrayIndexOutOfBoundsException ex) { + } catch (final ArrayIndexOutOfBoundsException ex) { } final List list = new ArrayList<>(); @@ -223,25 +303,25 @@ try { cs.getTarget().invoke(list, -1, 343); throw new RuntimeException("expected IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException ex) { + } catch (final IndexOutOfBoundsException ex) { } try { cs.getTarget().invoke(list, list.size(), 43543); throw new RuntimeException("expected IndexOutOfBoundsException"); - } catch (IndexOutOfBoundsException ex) { + } catch (final IndexOutOfBoundsException ex) { } } @Test(dataProvider = "flags") public void newObjectTest(final boolean publicLookup) { final MethodType mt = MethodType.methodType(Object.class, Object.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.NEW, mt); + final CallSite cs = createCallSite(publicLookup, NEW, mt); Object obj = null; try { obj = cs.getTarget().invoke(StaticClass.forClass(Date.class)); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -251,12 +331,12 @@ @Test(dataProvider = "flags") public void staticPropertyTest(final boolean publicLookup) { final MethodType mt = MethodType.methodType(Object.class, Class.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, "static", mt); + final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "static", mt); Object obj = null; try { obj = cs.getTarget().invoke(Object.class); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -265,7 +345,7 @@ try { obj = cs.getTarget().invoke(Date.class); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -274,7 +354,7 @@ try { obj = cs.getTarget().invoke(Object[].class); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -285,14 +365,14 @@ @Test(dataProvider = "flags") public void instanceMethodCallTest(final boolean publicLookup) { final MethodType mt = MethodType.methodType(Object.class, Object.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_METHOD, "getClass", mt); + final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getClass", mt); final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class); - final CallSite cs2 = createCallSite(publicLookup, StandardOperation.CALL, mt2); + final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); Object method = null; try { method = cs.getTarget().invoke(new Date()); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -301,7 +381,7 @@ Class clz = null; try { clz = (Class) cs2.getTarget().invoke(method, new Date()); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -311,11 +391,11 @@ @Test(dataProvider = "flags") public void instanceMethodCallTest2(final boolean publicLookup) { final MethodType mt = MethodType.methodType(Class.class, Object.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getClass", mt); + final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getClass", mt); Class clz = null; try { clz = (Class) cs.getTarget().invoke(new Date()); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -325,14 +405,14 @@ @Test(dataProvider = "flags") public void staticMethodCallTest(final boolean publicLookup) { final MethodType mt = MethodType.methodType(Object.class, StaticClass.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_METHOD, "getProperty", mt); + final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getProperty", mt); final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class); - final CallSite cs2 = createCallSite(publicLookup, StandardOperation.CALL, mt2); + final CallSite cs2 = createCallSite(publicLookup, CALL, mt2); Object method = null; try { method = cs.getTarget().invoke(StaticClass.forClass(System.class)); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -342,7 +422,7 @@ String str = null; try { str = (String) cs2.getTarget().invoke(method, null, "os.name"); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } Assert.assertEquals(str, System.getProperty("os.name")); @@ -351,12 +431,12 @@ @Test(dataProvider = "flags") public void staticMethodCallTest2(final boolean publicLookup) { final MethodType mt = MethodType.methodType(String.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getProperty", mt); + final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt); String str = null; try { str = (String) cs.getTarget().invoke(StaticClass.forClass(System.class), "os.name"); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } Assert.assertEquals(str, System.getProperty("os.name")); @@ -366,12 +446,12 @@ @Test(dataProvider = "flags") public void systemGetenvTest(final boolean publicLookup) { final MethodType mt = MethodType.methodType(Object.class, Object.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getenv", mt); + final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getenv", mt); try { cs.getTarget().invoke(StaticClass.forClass(System.class)); throw new RuntimeException("should not reach here in any case!"); - } catch (Throwable th) { + } catch (final Throwable th) { Assert.assertTrue(th instanceof SecurityException); } } @@ -380,12 +460,12 @@ @Test(dataProvider = "flags") public void systemGetPropertyTest(final boolean publicLookup) { final MethodType mt = MethodType.methodType(String.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getProperty", mt); + final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt); try { cs.getTarget().invoke(StaticClass.forClass(System.class), "java.home"); throw new RuntimeException("should not reach here in any case!"); - } catch (Throwable th) { + } catch (final Throwable th) { Assert.assertTrue(th instanceof SecurityException); } } @@ -394,12 +474,12 @@ @Test(dataProvider = "flags") public void systemLoadLibraryTest(final boolean publicLookup) { final MethodType mt = MethodType.methodType(void.class, Object.class, String.class); - final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "loadLibrary", mt); + final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "loadLibrary", mt); try { cs.getTarget().invoke(StaticClass.forClass(System.class), "foo"); throw new RuntimeException("should not reach here in any case!"); - } catch (Throwable th) { + } catch (final Throwable th) { if (publicLookup) { Assert.assertTrue(th instanceof IllegalAccessError); } else { diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java --- a/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -33,6 +33,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -44,6 +45,7 @@ import jdk.dynalink.CompositeOperation; import jdk.dynalink.DynamicLinkerFactory; import jdk.dynalink.NamedOperation; +import jdk.dynalink.NoSuchDynamicMethodException; import jdk.dynalink.Operation; import jdk.dynalink.StandardOperation; import jdk.dynalink.support.SimpleRelinkableCallSite; @@ -207,6 +209,30 @@ Assert.assertEquals("element2", map.get("name")); } + @Test + public static void testMissingMembersAtLinkTime() { + testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object()))); + testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object(), "newValue"))); + } + + @Test + public static void testMissingMembersAtRunTime() { + call(GET_ELEMENT, new ArrayList<>(), "foo"); + Stream.of(new HashMap(), new ArrayList(), new Object[0]).forEach((receiver) -> { + testPermutations(GETTER_PERMUTATIONS, (op) -> { System.err.println(op + " " + receiver.getClass().getName()); Assert.assertNull(call(op, receiver, "foo"));}); + // No assertion for the setter; we just expect it to silently succeed + testPermutations(SETTER_PERMUTATIONS, (op) -> call(op, receiver, "foo", "newValue")); + }); + } + + private static void expectNoSuchDynamicMethodException(final Runnable r) { + try { + r.run(); + Assert.fail("Should've thrown NoSuchDynamicMethodException"); + } catch(final NoSuchDynamicMethodException e) { + } + } + private static Operation[] GETTER_PERMUTATIONS = new Operation[] { GET_PROPERTY, GET_METHOD, @@ -240,6 +266,10 @@ testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test); } + private static void testPermutations(final Operation[] ops, final Consumer test) { + testPermutationsWithFilter(ops, (op)->true, ops.length, test); + } + private static void testPermutationsWithFilter(final Operation[] ops, final Predicate filter, final int expectedCount, final Consumer test) { final int[] counter = new int[1]; Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); }); diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/src/jdk/dynalink/beans/test/CallerSensitiveTest.java --- a/nashorn/test/src/jdk/dynalink/beans/test/CallerSensitiveTest.java Wed Jul 05 21:12:06 2017 +0200 +++ b/nashorn/test/src/jdk/dynalink/beans/test/CallerSensitiveTest.java Wed Jul 05 21:13:10 2017 +0200 @@ -33,6 +33,6 @@ public class CallerSensitiveTest { @Test public void testCallerSensitive() { - BeansLinker.getLinkerForClass(ClassLoaderAware.class); + new BeansLinker().getLinkerForClass(ClassLoaderAware.class); } } diff -r 3c05feabae49 -r 2dc4c11fe488 nashorn/test/src/jdk/internal/dynalink/beans/test/CallerSensitiveTest.java --- a/nashorn/test/src/jdk/internal/dynalink/beans/test/CallerSensitiveTest.java Wed Jul 05 21:12:06 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.dynalink.beans.test; - -import jdk.dynalink.beans.BeansLinker; -import jdk.nashorn.test.models.ClassLoaderAware; -import org.testng.annotations.Test; - -@SuppressWarnings("javadoc") -public class CallerSensitiveTest { - @Test - public void testCallerSensitive() { - BeansLinker.getLinkerForClass(ClassLoaderAware.class); - } -} diff -r 3c05feabae49 -r 2dc4c11fe488 test/make/TestJavaCompilation.gmk --- a/test/make/TestJavaCompilation.gmk Wed Jul 05 21:12:06 2017 +0200 +++ b/test/make/TestJavaCompilation.gmk Wed Jul 05 21:13:10 2017 +0200 @@ -239,6 +239,7 @@ $(eval $(call SetupJavaCompiler,BOOT_JAVAC, \ JAVAC := $(JAVAC), \ + DISABLE_SJAVAC := true, \ )) JAVA_SRC_ROOT1 := $(OUTPUT_DIR)/javaroot1