diff --git a/.hgtags b/.hgtags index b5ffdaee57d..744ce58f2fe 100644 --- a/.hgtags +++ b/.hgtags @@ -343,3 +343,4 @@ f242d4332f563648426a1b0fa02d8741beba19ef jdk9-b92 d00ad2d9049ac60815f70bff445e95df85648bd2 jdk-9+98 f9bcdce2df26678c3fe468130b535c0342c69b89 jdk-9+99 4379223f8806626852c46c52d4e7a27a584b406e jdk-9+100 +80f67512daa15cf37b4825c1c62a675d524d7c49 jdk-9+101 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 67085b3ac37..ad5eaa36b36 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -343,3 +343,4 @@ cf1dc4c035fb84693d4ae5ad818785cb4d1465d1 jdk9-b90 48987460c7d49a29013963ee44d090194396bb61 jdk-9+98 7c0577bea4c65d69c5bef67023a89d2efa4fb2f7 jdk-9+99 c1f30ac14db0eaff398429c04cd9fab92e1b4b2a jdk-9+100 +c4d72a1620835b5d657b7b6792c2879367d0154f jdk-9+101 diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index f6b11c8a3bf..be85de751eb 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -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 @@ AC_DEFUN_ONCE([BASIC_POST_CONFIG_OUTPUT], # 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 --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index 927bb522bcd..b34b2fb7a85 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -425,7 +425,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_OPTIMIZATION], # 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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], -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_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], 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 @@ AC_DEFUN([FLAGS_COMPILER_CHECK_ARGUMENTS], 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_DEFUN([FLAGS_COMPILER_CHECK_ARGUMENTS], 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_DEFUN([FLAGS_LINKER_CHECK_ARGUMENTS], 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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], *) 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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], ;; 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 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], # 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 --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index de0cce655ce..5ecfef8e2af 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -3451,6 +3451,31 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # 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 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -# 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 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1452261921 +DATE_WHEN_GENERATED=1452780299 ############################################################################### # @@ -45358,6 +45387,54 @@ $as_echo "$as_me: Rewriting BUILD_AR to \"$new_complete\"" >&6;} # "-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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $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 @@ $as_echo "$ac_cv_c_bigendian" >&6; } # 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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then : + 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 @@ $as_echo "$supports" >&6; } 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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu $as_echo "$supports" >&6; } if test "x$supports" = "xyes" ; then : + 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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $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 @@ $as_echo "yes (default)" >&6; } 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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $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 @@ $as_echo "$supports" >&6; } 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 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $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 @@ fi # 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 --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 3f5750dcc89..4254d86a4fb 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -75,8 +75,8 @@ AC_DEFUN([TOOLCHAIN_SETUP_FILENAME_PATTERNS], # 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 @@ AC_DEFUN_ONCE([TOOLCHAIN_MISC_CHECKS], # "-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 --git a/corba/.hgtags b/corba/.hgtags index 4a5ada00d4a..621cce92dcc 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -343,3 +343,4 @@ feb1bd85d7990dcf5584ca9e53104269c01db006 jdk-9+96 ea285530245cf4e0edf0479121a41347d3030eba jdk-9+98 180212ee1d8710691ba9944593dfc1ff3e4f1532 jdk-9+99 791d0d3ac0138faeb6110bd840a4545bc1950df2 jdk-9+100 +30dfb3bd3d06b4bb80a087babc0d1841edba187b jdk-9+101 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 271e5408b1a..2861744a267 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -503,3 +503,4 @@ de592ea5f7ba0f8a8c5afc03bd169f7690c72b6f jdk-9+97 e5b1a23be1e105417ba1c4c576ab373eb3fa2c2b jdk-9+98 f008e8cc10d5b3212fb22d58c96fa01d38654f19 jdk-9+99 bdb0acafc63c42e84d9d8195bf2e2b25ee9c3306 jdk-9+100 +9f45d3d57d6948cf526fbc2e2891a9a74ac6941a jdk-9+101 diff --git a/hotspot/src/share/vm/prims/nativeLookup.cpp b/hotspot/src/share/vm/prims/nativeLookup.cpp index fecef0a5055..d54f711c67d 100644 --- a/hotspot/src/share/vm/prims/nativeLookup.cpp +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,7 +124,7 @@ static JNINativeMethod lookup_special_native_methods[] = { { 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 --git a/hotspot/src/share/vm/prims/perf.cpp b/hotspot/src/share/vm/prims/perf.cpp index 435cb0146cb..1cbb9568298 100644 --- a/hotspot/src/share/vm/prims/perf.cpp +++ b/hotspot/src/share/vm/prims/perf.cpp @@ -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 --git a/jaxp/.hgtags b/jaxp/.hgtags index b016abbf315..89a01eeb6d6 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -343,3 +343,4 @@ c8d0845877a811ab4350935892f826929359a3ff jdk-9+95 52b01339235f24c93b679bd6b8fb36a1072ad0ac jdk-9+98 52774b544850c791f1d1c67db2601b33739b18c9 jdk-9+99 d45bcd374f6057851e3c2dcd45607cd362afadfa jdk-9+100 +d3e834ff74e724a2b92a558e18e8cbf81c6dbc59 jdk-9+101 diff --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java index ee6a29bfa26..7be69b9ea29 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java @@ -32,7 +32,6 @@ import java.net.URI; 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 java.util.stream.StreamSupport; 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 @@ class CatalogImpl extends GroupEntry implements Catalog { */ 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) { - this.features = CatalogFeatures.defaults(); - } else { - this.features = f; + throw new NullPointerException( + formatMessage(CatalogMessages.ERR_NULL_ARGUMENT, new Object[]{"CatalogFeatures"})); } - setPrefer(features.get(Feature.PREFER)); - setDeferred(features.get(Feature.DEFER)); - setResolve(features.get(Feature.RESOLVE)); + + if (file.length > 0) { + CatalogMessages.reportNPEOnNull("The path to the catalog file", file[0]); + } + + 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 @@ class CatalogImpl extends GroupEntry implements Catalog { } } + 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 --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java index 7539ec00be9..2e3c5b4f74b 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogManager.java @@ -38,33 +38,38 @@ public final class CatalogManager { } /** - * 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 @@ public final class CatalogManager { } /** - * 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 @@ public final class CatalogManager { } /** - * 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 --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java index 13c0e3791e4..76ba60dd2eb 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogUriResolver.java @@ -43,9 +43,9 @@ public interface CatalogUriResolver extends URIResolver { * 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 --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java index cf136f2cd59..f3f470243d5 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,6 +72,7 @@ final class RewriteSystem extends BaseEntry { public String getSystemIdStartString () { return systemIdStartString; } + /** * Get the rewritePrefix attribute. * @return The rewritePrefix attribute value. @@ -80,7 +81,6 @@ final class RewriteSystem extends BaseEntry { 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 @@ final class RewriteSystem extends BaseEntry { * @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 --git a/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java index 0aec4e41d29..f5c60b06730 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/RewriteUri.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,6 +72,7 @@ final class RewriteUri extends BaseEntry { public String getURIStartString () { return uriStartString; } + /** * Get the rewritePrefix attribute. * @return The rewritePrefix attribute value. @@ -91,14 +92,20 @@ final class RewriteUri extends BaseEntry { */ @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 --git a/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java b/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java index fe3d7111439..a9b75f2c42f 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java @@ -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 @@ public interface Source { * 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 --git a/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java b/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java index dc4e93e07f1..b977c14f035 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java @@ -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 @@ public class DOMSource implements Source { * * @param systemID Base URL for this DOM tree. */ + @Override public void setSystemId(String systemID) { this.systemID = systemID; } @@ -132,7 +133,25 @@ public class DOMSource implements Source { * * @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 --git a/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java b/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java index 0d573780e56..1829042e899 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java @@ -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 @@ public class SAXSource implements Source { * * @param systemId The system identifier as a URI string. */ + @Override public void setSystemId(String systemId) { if (null == inputSource) { @@ -162,6 +163,7 @@ public class SAXSource implements Source { * * @return Base URL for the Source, or null. */ + @Override public String getSystemId() { if (inputSource == null) { @@ -207,4 +209,22 @@ public class SAXSource implements Source { 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 --git a/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java b/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java index dd04b63fb69..43e17c6e14e 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java @@ -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 @@ public class StAXSource implements Source { * @throws UnsupportedOperationException Is always * thrown by this method. */ + @Override public void setSystemId(final String systemId) { throw new UnsupportedOperationException( @@ -229,8 +230,21 @@ public class StAXSource implements Source { * * @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 --git a/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java b/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java index 7627d5e3b55..a708db3017d 100644 --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java @@ -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 @@ public class StreamSource implements Source { * * @param systemId The system identifier as a URL string. */ + @Override public void setSystemId(String systemId) { this.systemId = systemId; } @@ -243,6 +246,7 @@ public class StreamSource implements Source { * @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 @@ public class StreamSource implements Source { 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 --git a/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java b/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java index 9498da395c7..f05d23f5108 100644 --- a/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java @@ -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 @@ public class InputSource { 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 --git a/jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java b/jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java index cde6fafa8cc..a0066a9a0e5 100644 --- a/jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java +++ b/jaxp/test/javax/xml/jaxp/functional/catalog/DeferFeatureTest.java @@ -56,23 +56,14 @@ public class DeferFeatureTest { @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 --git a/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java b/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java index 291d86d02c0..0e0ff9f194c 100644 --- a/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java +++ b/jaxp/test/javax/xml/jaxp/libs/catalog/CatalogTestUtils.java @@ -83,7 +83,7 @@ final class CatalogTestUtils { * 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 @@ final class CatalogTestUtils { */ 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 @@ final class CatalogTestUtils { */ 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 --git a/jaxp/test/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java index a7f18083d30..8269f05eee1 100644 --- a/jaxp/test/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java +++ b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/JAXPTestUtilities.java @@ -89,7 +89,7 @@ public class JAXPTestUtilities { /** * 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 --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java index a9515da6676..08830042132 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,14 +27,13 @@ import javax.xml.catalog.CatalogFeatures; 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,11 +41,65 @@ import org.xml.sax.XMLReader; 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 @@ -61,7 +114,7 @@ public class CatalogTest { } 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 @@ public class CatalogTest { 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 --git a/jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteCatalog.xml b/jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteCatalog.xml new file mode 100644 index 00000000000..8ef5c9b0117 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/rewriteCatalog.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/unittest/common/Sources.java b/jaxp/test/javax/xml/jaxp/unittest/common/Sources.java new file mode 100644 index 00000000000..f3deba62395 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/common/Sources.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +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 --git a/jaxws/.hgtags b/jaxws/.hgtags index 4f84f88fb74..5450b82df39 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -346,3 +346,4 @@ b55cebc47555293cf9c2aefb3bf63c56e847ab19 jdk-9+96 67c84077edc3db6b24998b35970b37c01aae985e jdk-9+98 97b31ca0dd77483cf20ff99a033a455673639578 jdk-9+99 d0a97e57d2336238edf6a4cd60aafe67deb7258d jdk-9+100 +3e99318616da903e0dc8f07f9f9203dc1bd49921 jdk-9+101 diff --git a/jdk/make/CompileDemos.gmk b/jdk/make/CompileDemos.gmk index 73f3edff8a0..ac2ce41de82 100644 --- a/jdk/make/CompileDemos.gmk +++ b/jdk/make/CompileDemos.gmk @@ -38,7 +38,8 @@ include TextFileProcessing.gmk include ZipArchive.gmk # Prepare the find cache. -$(eval $(call FillCacheFind, $(JDK_TOPDIR)/src)) +$(eval $(call FillCacheFind, $(wildcard $(JDK_TOPDIR)/src/demo \ + $(JDK_TOPDIR)/src/*/demo))) # Append demo goals to this variable. TARGETS = diff --git a/jdk/make/CompileTools.gmk b/jdk/make/CompileTools.gmk new file mode 100644 index 00000000000..27aaffaafdb --- /dev/null +++ b/jdk/make/CompileTools.gmk @@ -0,0 +1,83 @@ +# +# Copyright (c) 2011, 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. +# + +default: all + +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include SetupJavaCompilers.gmk + +################################################################################ + +JIMAGE_PKGS := \ + jdk/internal/jimage \ + jdk/internal/jrtfs \ + # + +$(eval $(call SetupJavaCompilation,BUILD_INTERIM_JIMAGE, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ + INCLUDES := $(JIMAGE_PKGS), \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes)) + +TARGETS += $(BUILD_INTERIM_JIMAGE) + +# Because of the explicit INCLUDES in the compilation setup above, the service provider +# file will not be copied unless META-INF/services would also be added to the INCLUDES. +# Adding META-INF/services would include all files in that directory when only the one +# is needed, which is why this explicit copy is defined instead. +$(eval $(call SetupCopyFiles,COPY_JIMAGE_SERVICE_PROVIDER, \ + SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ + DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes, \ + FILES := META-INF/services/java.nio.file.spi.FileSystemProvider)) + +TARGETS += $(COPY_JIMAGE_SERVICE_PROVIDER) + +################################################################################ + +$(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \ + SETUP := GENERATE_OLDBYTECODE, \ + ADD_JAVAC_FLAGS := -Xbootclasspath/p:$(call PathList, \ + $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes \ + $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes), \ + SRC := $(JDK_TOPDIR)/make/src/classes $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ + COPY := boot.modules ext.modules)) + +$(BUILD_TOOLS_JDK): $(BUILD_INTERIM_JIMAGE) $(COPY_JIMAGE_SERVICE_PROVIDER) + +TARGETS += $(BUILD_TOOLS_JDK) + +$(eval $(call SetupCopyFiles,COPY_NIMBUS_TEMPLATES, \ + SRC := $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus, \ + DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources, \ + FILES := $(wildcard $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template))) + +TARGETS += $(COPY_NIMBUS_TEMPLATES) + +################################################################################ + +all: $(TARGETS) diff --git a/jdk/make/CopySamples.gmk b/jdk/make/CopySamples.gmk index be20f92fd17..09d0bf7ba44 100644 --- a/jdk/make/CopySamples.gmk +++ b/jdk/make/CopySamples.gmk @@ -28,41 +28,38 @@ default: all include $(SPEC) include MakeBase.gmk +################################################################################ + SAMPLE_TARGET_DIR := $(SUPPORT_OUTPUTDIR)/sample/image SAMPLE_SOURCE_DIR := $(JDK_TOPDIR)/src/sample/share -SAMPLE_CLOSED_SOURCE_DIR := $(JDK_TOPDIR)/src/closed/sample/share SAMPLE_SOLARIS_SOURCE_DIR := $(JDK_TOPDIR)/src/sample/solaris # Exclude the vm directory -SAMPLE_FIND_FILTER := -name vm -prune -o +$(eval $(call SetupCopyFiles, COPY_SHARE_SAMPLES, \ + SRC := $(SAMPLE_SOURCE_DIR), \ + DEST := $(SAMPLE_TARGET_DIR), \ + FILES := $(filter-out $(SAMPLE_SOURCE_DIR)/vm/%, \ + $(call CacheFind, $(SAMPLE_SOURCE_DIR))), \ +)) -SAMPLE_SOURCE := $(shell $(FIND) $(SAMPLE_SOURCE_DIR) $(SAMPLE_FIND_FILTER) -type f -print) -SAMPLE_TARGET := $(subst $(SAMPLE_SOURCE_DIR),$(SAMPLE_TARGET_DIR),$(SAMPLE_SOURCE)) - -ifndef OPENJDK -# Exclude Main.java in EbayClient dir - SAMPLE_CLOSED_SOURCE := $(shell $(FIND) $(SAMPLE_CLOSED_SOURCE_DIR) -type f -print | $(GREP) -v EbayClient/Main.java) - SAMPLE_CLOSED_TARGET := $(subst $(SAMPLE_CLOSED_SOURCE_DIR),$(SAMPLE_TARGET_DIR),$(SAMPLE_CLOSED_SOURCE)) - SAMPLE_TARGET += $(SAMPLE_CLOSED_TARGET) -endif +TARGETS += $(COPY_SHARE_SAMPLES) ifneq (, $(filter $(OPENJDK_TARGET_OS), solaris macosx)) - SAMPLE_SOLARIS_SOURCE := $(shell $(FIND) $(SAMPLE_SOLARIS_SOURCE_DIR) -type f -print) - SAMPLE_SOLARIS_TARGET := $(subst $(SAMPLE_SOLARIS_SOURCE_DIR),$(SAMPLE_TARGET_DIR),$(SAMPLE_SOLARIS_SOURCE)) - SAMPLE_TARGET += $(SAMPLE_SOLARIS_TARGET) + $(eval $(call SetupCopyFiles, COPY_SOLARIS_SAMPLES, \ + SRC := $(SAMPLE_SOLARIS_SOURCE_DIR), \ + DEST := $(SAMPLE_TARGET_DIR), \ + FILES := $(call CacheFind, $(SAMPLE_SOLARIS_SOURCE_DIR)), \ + )) + + TARGETS += $(COPY_SOLARIS_SAMPLES) endif -$(SAMPLE_TARGET_DIR)/dtrace/%: $(SAMPLE_SOLARIS_SOURCE_DIR)/dtrace/% - $(call install-file) +################################################################################ -$(SAMPLE_TARGET_DIR)/webservices/%: $(SAMPLE_CLOSED_SOURCE_DIR)/webservices/% - $(call install-file) +$(eval $(call IncludeCustomExtension, jdk, CopySamples.gmk)) -$(SAMPLE_TARGET_DIR)/%: $(SAMPLE_SOURCE_DIR)/% - $(call install-file) +################################################################################ -COPY_FILES += $(SAMPLE_TARGET) +all: $(TARGETS) -all: $(COPY_FILES) - -.PHONY: all +.PHONY: all default diff --git a/jdk/make/Import.gmk b/jdk/make/Import.gmk index d4c5654aeac..42155494fb2 100644 --- a/jdk/make/Import.gmk +++ b/jdk/make/Import.gmk @@ -48,7 +48,7 @@ endif ifneq ($(STATIC_BUILD), true) JSIG_IMPORT = jsig.* else - JSIG_IMPORT = + JSIG_IMPORT = endif HOTSPOT_BASE_IMPORT_FILES := \ diff --git a/jdk/make/Tools.gmk b/jdk/make/Tools.gmk index 7668928ff65..cd8d7e867a1 100644 --- a/jdk/make/Tools.gmk +++ b/jdk/make/Tools.gmk @@ -26,31 +26,14 @@ ifndef _TOOLS_GMK _TOOLS_GMK := 1 -default: all - -include $(SPEC) -include MakeBase.gmk include JavaCompilation.gmk -include NativeCompilation.gmk -include SetupJavaCompilers.gmk ################################################################################ - -$(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \ - SETUP := GENERATE_OLDBYTECODE, \ - ADD_JAVAC_FLAGS := -Xbootclasspath/p:$(call PathList, \ - $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes \ - $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes), \ - SRC := $(JDK_TOPDIR)/make/src/classes $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes, \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ - COPY := boot.modules ext.modules)) - -$(eval $(call SetupCopyFiles,COPY_NIMBUS_TEMPLATES, \ - SRC := $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus, \ - DEST := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes/build/tools/generatenimbus/resources, \ - FILES := $(wildcard $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/*.template))) - -BUILD_TOOLS_JDK += $(COPY_NIMBUS_TEMPLATES) +# To avoid reevaluating the compilation setup for the tools each time this file +# is included, the actual compilation is handled by CompileTools.gmk. The +# following trick is used to be able to declare a dependency on the built tools. +BUILD_TOOLS_JDK := $(call SetupJavaCompilationCompileTarget, \ + BUILD_TOOLS_JDK, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) ################################################################################ @@ -135,34 +118,4 @@ TOOL_IMAGEBUILDER = $(JAVA_SMALL) -Xbootclasspath/p:$(BUILDTOOLS_OUTPUTDIR)/inte -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes $(JDK_OUTPUTDIR)) \ build.tools.module.ImageBuilder -########################################################################################## - -JIMAGE_PKGS := \ - jdk/internal/jimage \ - jdk/internal/jrtfs \ - # - -$(eval $(call SetupJavaCompilation,BUILD_INTERIM_JIMAGE, \ - SETUP := GENERATE_OLDBYTECODE, \ - SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ - INCLUDES := $(JIMAGE_PKGS), \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes)) - -# Because of the explicit INCLUDES in the compilation setup above, the service provider -# file will not be copied unless META-INF/services would also be added to the INCLUDES. -# Adding META-INF/services would include all files in that directory when only the one -# is needed, which is why this explicit copy is defined instead. -$(eval $(call SetupCopyFiles,COPY_JIMAGE_SERVICE_PROVIDER, \ - SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ - DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes, \ - FILES := META-INF/services/java.nio.file.spi.FileSystemProvider)) - -########################################################################################## - -$(BUILD_TOOLS_JDK): $(BUILD_INTERIM_JIMAGE) $(COPY_JIMAGE_SERVICE_PROVIDER) - -java-tools: $(BUILD_TOOLS_JDK) - -all: java-tools - endif # _TOOLS_GMK diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk index 46687333361..ed8e42ae272 100644 --- a/jdk/make/copy/Copy-java.base.gmk +++ b/jdk/make/copy/Copy-java.base.gmk @@ -187,27 +187,31 @@ TARGETS += $(POLICY_DST) ifeq ($(CACERTS_FILE), ) CACERTS_FILE := $(JDK_TOPDIR)/src/java.base/share/conf/security/cacerts endif + CACERTS_DST := $(LIB_DST_DIR)/security/cacerts $(CACERTS_DST): $(CACERTS_FILE) + $(call LogInfo, Copying $(patsubst $(OUTPUT_ROOT)/%, %, $@)) $(call install-file) TARGETS += $(CACERTS_DST) ################################################################################ -$(CONF_DST_DIR)/net.properties: $(JDK_TOPDIR)/src/java.base/share/conf/net.properties - $(ECHO) $(LOG_INFO) Copying $(@F) - $(call install-file) +$(eval $(call SetupCopyFiles, COPY_NET_PROPERTIES, \ + FILES := $(JDK_TOPDIR)/src/java.base/share/conf/net.properties, \ + DEST := $(CONF_DST_DIR), \ +)) -TARGETS += $(CONF_DST_DIR)/net.properties +TARGETS += $(COPY_NET_PROPERTIES) ifeq ($(OPENJDK_TARGET_OS), solaris) - $(CONF_DST_DIR)/sdp/sdp.conf.template: $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/sdp/sdp.conf.template - $(ECHO) $(LOG_INFO) Copying $(@F) - $(call install-file) + $(eval $(call SetupCopyFiles, COPY_SDP_CONF, \ + FILES := $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/sdp/sdp.conf.template, \ + DEST := $(CONF_DST_DIR)/sdp, \ + )) - TARGETS += $(CONF_DST_DIR)/sdp/sdp.conf.template + TARGETS += $(COPY_SDP_CONF) endif ################################################################################ diff --git a/jdk/make/gendata/GendataBreakIterator.gmk b/jdk/make/gendata/GendataBreakIterator.gmk index 38bf0e537bb..b2827da2f0f 100644 --- a/jdk/make/gendata/GendataBreakIterator.gmk +++ b/jdk/make/gendata/GendataBreakIterator.gmk @@ -68,8 +68,8 @@ BIFILES_TH := $(LD_DATA_PKG_DIR)/th/WordBreakIteratorData_th \ $(BIFILES): $(BASE_DATA_PKG_DIR)/_the.bifiles $(BASE_DATA_PKG_DIR)/_the.bifiles: JAVA_FLAGS += -Xbootclasspath/p:$(BREAK_ITERATOR_CLASSES) $(BASE_DATA_PKG_DIR)/_the.bifiles: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKITERATOR) - $(ECHO) $(LOG_INFO) "Generating BreakIteratorData" - $(MKDIR) -p $(@D) + $(call LogInfo, Generating BreakIteratorData) + $(call MakeDir, $(@D)) $(RM) $(BIFILES) $(TOOL_GENERATEBREAKITERATORDATA) \ -o $(@D) \ @@ -79,8 +79,8 @@ $(BASE_DATA_PKG_DIR)/_the.bifiles: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKIT $(BIFILES_TH): $(LD_DATA_PKG_DIR)/_the.bifiles_th $(LD_DATA_PKG_DIR)/_the.bifiles_th: JAVA_FLAGS += -Xbootclasspath/p:$(BREAK_ITERATOR_CLASSES) $(LD_DATA_PKG_DIR)/_the.bifiles_th: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKITERATOR) - $(ECHO) $(LOG_INFO) "Generating BreakIteratorData_th" - $(MKDIR) -p $(@D)/th + $(call LogInfo, Generating BreakIteratorData_th) + $(call MakeDir, $(@D)/th) $(RM) $(BIFILES_TH) $(TOOL_GENERATEBREAKITERATORDATA) \ -o $(@D) \ diff --git a/jdk/make/gendata/GendataHtml32dtd.gmk b/jdk/make/gendata/GendataHtml32dtd.gmk index 1adb85ad0aa..2bc0e708673 100644 --- a/jdk/make/gendata/GendataHtml32dtd.gmk +++ b/jdk/make/gendata/GendataHtml32dtd.gmk @@ -27,7 +27,7 @@ GENDATA_HTML32DTD := HTML32DTD = $(JDK_OUTPUTDIR)/modules/java.desktop/javax/swing/text/html/parser/html32.bdtd $(HTML32DTD): $(BUILD_TOOLS_JDK) - $(ECHO) "Generating HTML DTD file" + $(call LogInfo, Generating HTML DTD file) $(MKDIR) -p $(@D) $(RM) $@ ($(TOOL_DTDBUILDER) $(LOG_INFO) html32 > $@) || exit 1 diff --git a/jdk/make/gendata/GendataPolicyJars.gmk b/jdk/make/gendata/GendataPolicyJars.gmk index 82e2e424446..ffed629f011 100644 --- a/jdk/make/gendata/GendataPolicyJars.gmk +++ b/jdk/make/gendata/GendataPolicyJars.gmk @@ -87,8 +87,7 @@ $(eval $(call SetupJarArchive, BUILD_US_EXPORT_POLICY_JAR, \ $(US_EXPORT_POLICY_JAR_LIMITED): \ $(US_EXPORT_POLICY_JAR_UNLIMITED) - $(ECHO) $(LOG_INFO) \ - Copying unlimited $(patsubst $(OUTPUT_ROOT)/%,%,$@) + $(call LogInfo, Copying unlimited $(patsubst $(OUTPUT_ROOT)/%,%,$@)) $(install-file) TARGETS += $(US_EXPORT_POLICY_JAR_LIMITED) $(US_EXPORT_POLICY_JAR_UNLIMITED) @@ -99,7 +98,7 @@ ifeq ($(UNLIMITED_CRYPTO), true) else $(US_EXPORT_POLICY_JAR_DST): $(US_EXPORT_POLICY_JAR_LIMITED) $(install-file) -endif +endif ifndef OPENJDK ifneq ($(UNLIMITED_CRYPTO), true) diff --git a/jdk/make/gensrc/Gensrc-jdk.charsets.gmk b/jdk/make/gensrc/Gensrc-jdk.charsets.gmk index fc6c481f523..c5f79ce54c9 100644 --- a/jdk/make/gensrc/Gensrc-jdk.charsets.gmk +++ b/jdk/make/gensrc/Gensrc-jdk.charsets.gmk @@ -46,30 +46,34 @@ $(CHARSET_DONE_CS)-extcs: $(CHARSET_DATA_DIR)/charsets \ $(wildcard $(CHARSET_DATA_DIR)/$(CHARSET_STANDARD_OS)) \ $(CHARSET_TEMPLATES) $(CHARSET_EXTENDED_JAVA_TEMPLATES) \ $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call LogInfo, Generating jdk.charsets extcs) + $(call MakeDir, $(@D)) $(TOOL_CHARSETMAPPING) $(CHARSET_DATA_DIR) $(CHARSET_GENSRC_JAVA_DIR_CS) \ extcs charsets $(CHARSET_STANDARD_OS) \ $(CHARSET_EXTENDED_JAVA_TEMPLATES) \ $(CHARSET_EXTENDED_JAVA_DIR) \ $(CHARSET_COPYRIGHT_HEADER) \ - $(LOG_INFO) + $(LOG_DEBUG) $(TOUCH) '$@' $(CHARSET_DONE_CS)-hkscs: $(CHARSET_COPYRIGHT_HEADER)/HKSCS.java \ $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call LogInfo, Generating jdk.charsets hkscs) + $(call MakeDir, $(@D)) $(TOOL_CHARSETMAPPING) $(CHARSET_DATA_DIR) $(CHARSET_GENSRC_JAVA_DIR_CS) hkscs '$<' $(TOUCH) '$@' $(CHARSET_DONE_CS)-euctw: $(CHARSET_COPYRIGHT_HEADER)/EUC_TW.java \ $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call LogInfo, Generating jdk.charsets euctw) + $(call MakeDir, $(@D)) $(TOOL_CHARSETMAPPING) $(CHARSET_DATA_DIR) $(CHARSET_GENSRC_JAVA_DIR_CS) euctw '$<' $(TOUCH) '$@' $(CHARSET_GENSRC_JAVA_DIR_CS)/sjis0213.dat: $(CHARSET_DATA_DIR)/sjis0213.map \ $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call LogInfo, Generating $(patsubst $(OUTPUT_ROOT)/%, %, $@)) + $(call MakeDir, $(@D)) $(TOOL_CHARSETMAPPING) '$<' '$@' sjis0213 GENSRC_JDK_CHARSETS += \ @@ -86,4 +90,3 @@ jdk.charsets: $(GENSRC_JDK_CHARSETS) all: jdk.charsets .PHONY: all jdk.charsets - diff --git a/jdk/make/gensrc/Gensrc-jdk.jdi.gmk b/jdk/make/gensrc/Gensrc-jdk.jdi.gmk index 036388395fc..21186f3af08 100644 --- a/jdk/make/gensrc/Gensrc-jdk.jdi.gmk +++ b/jdk/make/gensrc/Gensrc-jdk.jdi.gmk @@ -40,19 +40,18 @@ $(HEADER_FILE): $(JDWP_SPEC_FILE) $(BUILD_TOOLS_JDK) # Touch the target of this rule at the end to avoid triggering false rebuilds $(JAVA_FILE): $(JDWP_SPEC_FILE) $(BUILD_TOOLS_JDK) $(HEADER_FILE) - $(MKDIR) -p $(@D) - $(MKDIR) -p $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent + $(call LogInfo, Creating JDWP.java and JDWPCommands.h from jdwp.spec) + $(call MakeDir, $(@D) $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent) $(RM) $@ $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent/JDWPCommands.h - $(ECHO) $(LOG_INFO) Creating JDWP.java and JDWPCommands.h from jdwp.spec $(TOOL_JDWPGEN) $< -jdi $@ -include \ $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent/JDWPCommands.h $(TOUCH) $@ $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html: $(JDWP_SPEC_FILE) \ $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call LogInfo, Creating $(@F) from jdwp.spec) + $(call MakeDir, $(@D)) $(RM) $@ - $(ECHO) $(LOG_INFO) Creating $(@F) from jdwp.spec $(TOOL_JDWPGEN) $< -doc $@ GENSRC_JDWP := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/com/sun/tools/jdi/JDWP.java \ @@ -63,7 +62,7 @@ GENSRC_JDK_JDI += $(GENSRC_JDWP) ################################################################################ define process-provider - $(MKDIR) -p $(@D) + $(call MakeDir, $(@D)) $(CAT) $^ | $(SED) -e "s/^#\[$(OPENJDK_TARGET_OS)\]//" > $@ endef diff --git a/jdk/make/gensrc/GensrcBuffer.gmk b/jdk/make/gensrc/GensrcBuffer.gmk index 2f5d789cd60..34c67125aea 100644 --- a/jdk/make/gensrc/GensrcBuffer.gmk +++ b/jdk/make/gensrc/GensrcBuffer.gmk @@ -23,7 +23,7 @@ # questions. # -GENSRC_BUFFER := +GENSRC_BUFFER := GENSRC_BUFFER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio @@ -31,9 +31,9 @@ GENSRC_BUFFER_SRC := $(JDK_TOPDIR)/src/java.base/share/classes/java/nio ### -$(GENSRC_BUFFER_DST)/_the.buffer.dir: - $(ECHO) "Generating buffer classes" - $(MKDIR) -p $(@D) +$(GENSRC_BUFFER_DST)/_the.buffer.dir: + $(call LogInfo, Generating buffer classes) + $(call MakeDir, $(@D)) $(TOUCH) $@ define fixRw diff --git a/jdk/make/gensrc/GensrcCharacterData.gmk b/jdk/make/gensrc/GensrcCharacterData.gmk index b0b5eddacde..3994902edb2 100644 --- a/jdk/make/gensrc/GensrcCharacterData.gmk +++ b/jdk/make/gensrc/GensrcCharacterData.gmk @@ -35,8 +35,8 @@ UNICODEDATA = $(JDK_TOPDIR)/make/data/unicodedata define SetupCharacterData $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/$1.java: \ $(CHARACTERDATA)/$1.java.template - $(MKDIR) -p $$(@D) - $(ECHO) $(LOG_INFO) Generating $1.java + $$(call LogInfo, Generating $1.java) + $$(call MakeDir, $$(@D)) $(TOOL_GENERATECHARACTER) $2 \ -template $(CHARACTERDATA)/$1.java.template \ -spec $(UNICODEDATA)/UnicodeData.txt \ @@ -56,7 +56,7 @@ $(eval $(call SetupCharacterData,CharacterData0E, -plane 14, 11 4 1)) # Copy two Java files that need no preprocessing. $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/%.java: $(CHARACTERDATA)/%.java.template - $(ECHO) $(LOG_INFO) Generating $(@F) + $(call LogInfo, Generating $(@F)) $(call install-file) GENSRC_CHARACTERDATA += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/CharacterDataUndefined.java \ diff --git a/jdk/make/gensrc/GensrcCharsetMapping.gmk b/jdk/make/gensrc/GensrcCharsetMapping.gmk index 0218d4a1039..c904c54de23 100644 --- a/jdk/make/gensrc/GensrcCharsetMapping.gmk +++ b/jdk/make/gensrc/GensrcCharsetMapping.gmk @@ -44,13 +44,13 @@ $(CHARSET_DONE_BASE)-stdcs: $(CHARSET_DATA_DIR)/charsets \ $(wildcard $(CHARSET_DATA_DIR)/$(CHARSET_STANDARD_OS)) \ $(CHARSET_TEMPLATES) $(CHARSET_STANDARD_JAVA_TEMPLATES) \ $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(@D) + $(call LogInfo, Generating java.base charset mapping) + $(call MakeDir, $(@D)) $(TOOL_CHARSETMAPPING) $(CHARSET_DATA_DIR) $(CHARSET_GENSRC_JAVA_DIR_BASE) \ stdcs charsets $(CHARSET_STANDARD_OS) \ $(CHARSET_STANDARD_JAVA_TEMPLATES) $(CHARSET_EXTSRC_DIR) \ $(CHARSET_COPYRIGHT_HEADER) \ - $(LOG_INFO) + $(LOG_DEBUG) $(TOUCH) '$@' GENSRC_JAVA_BASE += $(CHARSET_DONE_BASE)-stdcs - diff --git a/jdk/make/gensrc/GensrcExceptions.gmk b/jdk/make/gensrc/GensrcExceptions.gmk index 398a8857963..947cd019eec 100644 --- a/jdk/make/gensrc/GensrcExceptions.gmk +++ b/jdk/make/gensrc/GensrcExceptions.gmk @@ -32,21 +32,12 @@ GENSRC_EXCEPTIONS_CMD := $(JDK_TOPDIR)/make/scripts/genExceptions.sh GENSRC_EXCEPTIONS_SRC_DIRS := . charset channels -### - -$(GENSRC_EXCEPTIONS_DST)/_the.exceptions.dir: - $(ECHO) "Generating exceptions classes" - $(MKDIR) -p $(@D) - $(TOUCH) $@ - - -### - $(GENSRC_EXCEPTIONS_DST)/_the.%.marker: $(GENSRC_EXCEPTIONS_SRC)/%/exceptions \ - $(GENSRC_EXCEPTIONS_CMD) \ - $(GENSRC_EXCEPTIONS_DST)/_the.exceptions.dir - $(MKDIR) -p $(@D)/$* - SCRIPTS="$(JDK_TOPDIR)/make/scripts" NAWK="$(NAWK)" SH="$(SH)" $(SH) $(GENSRC_EXCEPTIONS_CMD) $< $(@D)/$* $(LOG_INFO) + $(GENSRC_EXCEPTIONS_CMD) + $(call LogInfo, Generating exceptions java.nio $*) + $(call MakeDir, $(@D)/$*) + SCRIPTS="$(JDK_TOPDIR)/make/scripts" NAWK="$(NAWK)" SH="$(SH)" $(SH) \ + $(GENSRC_EXCEPTIONS_CMD) $< $(@D)/$* $(LOG_DEBUG) $(TOUCH) $@ GENSRC_EXCEPTIONS += $(foreach D,$(GENSRC_EXCEPTIONS_SRC_DIRS),$(GENSRC_EXCEPTIONS_DST)/_the.$(D).marker) diff --git a/jdk/make/gensrc/GensrcIcons.gmk b/jdk/make/gensrc/GensrcIcons.gmk index 6e1b5df596f..32ab58a3137 100644 --- a/jdk/make/gensrc/GensrcIcons.gmk +++ b/jdk/make/gensrc/GensrcIcons.gmk @@ -65,8 +65,8 @@ GENSRC_AWT_ICONS_DST_NAME = AWTIcon$(2)_$(subst .,_,$(subst -,_,$(1))) ################################################################################ $(GENSRC_AWT_ICONS_TMP)/_the.icons.dir: - $(ECHO) Generating icon classes - $(MKDIR) -p $(GENSRC_AWT_ICONS_DST) + $(call LogInfo, Generating icon classes) + $(call MakeDir, $(GENSRC_AWT_ICONS_DST)) $(TOUCH) $@ ################################################################################ @@ -121,8 +121,9 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) endif $(GENSRC_OSX_ICONS): $(GENSRC_OSX_ICONS_SRC) $(BUILD_TOOLS_JDK) + $(call LogInfo, Generating $(patsubst $(OUTPUT_ROOT)/%, %, $@)) + $(call MakeDir, $(@D)) $(RM) $@ $@.tmp - $(MKDIR) -p $(dir $@) $(ECHO) "static unsigned char sAWTIconData[] = { " >> $@.tmp $(CAT) $< | $(TOOL_OSX_TOBIN) >> $@.tmp $(ECHO) "};" >> $@.tmp diff --git a/jdk/make/gensrc/GensrcLocaleData.gmk b/jdk/make/gensrc/GensrcLocaleData.gmk index 71b091bac8a..602a4f4752f 100644 --- a/jdk/make/gensrc/GensrcLocaleData.gmk +++ b/jdk/make/gensrc/GensrcLocaleData.gmk @@ -28,8 +28,9 @@ # into LocaleDataMetaInfo.java # First go look for all locale files -LOCALE_FILES := $(shell $(FIND) $(JDK_TOPDIR)/src/java.base/share/classes \ - $(JDK_TOPDIR)/src/jdk.localedata/share/classes \ +LOCALE_FILES := $(shell $(FIND) \ + $(JDK_TOPDIR)/src/$(MODULE)/share/classes/sun/text/resources \ + $(JDK_TOPDIR)/src/$(MODULE)/share/classes/sun/util/resources \ -name "FormatData_*.java" -o -name "FormatData_*.properties" -o \ -name "CollationData_*.java" -o -name "CollationData_*.properties" -o \ -name "TimeZoneNames_*.java" -o -name "TimeZoneNames_*.properties" -o \ @@ -42,17 +43,21 @@ LOCALE_FILES := $(shell $(FIND) $(JDK_TOPDIR)/src/java.base/share/classes \ LOCALE_RESOURCES := $(sort $(subst .properties,,$(subst .java,,$(notdir $(LOCALE_FILES))))) # Include the list of resources found during the previous compile. --include $(SUPPORT_OUTPUTDIR)/gensrc/_the.locale_resources +-include $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/_the.locale_resources MISSING_RESOURCES := $(filter-out $(LOCALE_RESOURCES), $(PREV_LOCALE_RESOURCES)) NEW_RESOURCES := $(filter-out $(PREV_LOCALE_RESOURCES), $(LOCALE_RESOURCES)) ifneq (, $(MISSING_RESOURCES)$(NEW_RESOURCES)) # There is a difference in the number of supported resources. Trigger a regeneration. - $(shell $(RM) $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/BaseLocaleDataMetaInfo.java \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonBaseLocaleDataMetaInfo.java \ - $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/cldr/CLDRBaseLocaleDataMetaInfo.java \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo_jdk_localedata.java) + ifeq ($(MODULE), java.base) + $(shell $(RM) $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/BaseLocaleDataMetaInfo.java \ + $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/cldr/CLDRBaseLocaleDataMetaInfo.java) + endif + ifeq ($(MODULE), jdk.localedata) + $(shell $(RM) $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonBaseLocaleDataMetaInfo.java \ + $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo_jdk_localedata.java) + endif endif # The base locales @@ -121,18 +126,18 @@ SED_NONBASEARGS += -e 's/$(HASH)AvailableLocales_Locales$(HASH)/$(sort $(ALL_NON $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/BaseLocaleDataMetaInfo.java: \ $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template + $(call LogInfo, Creating sun/util/locale/provider/BaseLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources) $(MKDIR) -p $(@D) - $(ECHO) Creating sun/util/locale/provider/BaseLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources. $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" \ - > $(SUPPORT_OUTPUTDIR)/gensrc/_the.locale_resources + > $(SUPPORT_OUTPUTDIR)/gensrc/java.base/_the.locale_resources $(SED) $(SED_BASEARGS) $< > $@ $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonBaseLocaleDataMetaInfo.java: \ $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template + $(call LogInfo, Creating sun/util/resources/provider/NonBaseLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources) $(MKDIR) -p $(@D) - $(ECHO) Creating sun/util/resources/provider/NonBaseLocaleDataMetaInfo.java from $(words $(LOCALE_RESOURCES)) found resources. $(PRINTF) "PREV_LOCALE_RESOURCES:=$(LOCALE_RESOURCES)" \ - > $(SUPPORT_OUTPUTDIR)/gensrc/_the.locale_resources + > $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/_the.locale_resources $(SED) $(SED_NONBASEARGS) $< > $@ GENSRC_BASELOCALEDATA := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/BaseLocaleDataMetaInfo.java diff --git a/jdk/make/gensrc/GensrcMisc.gmk b/jdk/make/gensrc/GensrcMisc.gmk index 6e3cc38950d..bc70e0e01f0 100644 --- a/jdk/make/gensrc/GensrcMisc.gmk +++ b/jdk/make/gensrc/GensrcMisc.gmk @@ -50,7 +50,7 @@ GENSRC_SOR_BIN := $(BUILDTOOLS_OUTPUTDIR)/native/genSocketOptionRegistry SOR_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSRC_SOR_SRC)/$(GENSRC_SOR_SRC_FILE) | \ $(NAWK) '/^.*Copyright.*Oracle/ { printf "%s %s",$$4,$$5 }') -$(eval $(call SetupNativeCompilation,BUILD_GENSRC_SOR_EXE, \ +$(eval $(call SetupNativeCompilation, BUILD_GENSRC_SOR_EXE, \ SRC := $(GENSRC_SOR_SRC), \ INCLUDE_FILES := $(GENSRC_SOR_SRC_FILE), \ TOOLCHAIN := TOOLCHAIN_BUILD, \ @@ -86,7 +86,7 @@ ifneq ($(OPENJDK_TARGET_OS), windows) UC_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSRC_UC_SRC)/$(GENSRC_UC_SRC_FILE) | \ $(NAWK) '/^.*Copyright.*Oracle/ { printf "%s %s",$$4,$$5 }') - $(eval $(call SetupNativeCompilation,BUILD_GENSRC_UC_EXE, \ + $(eval $(call SetupNativeCompilation, BUILD_GENSRC_UC_EXE, \ SRC := $(GENSRC_UC_SRC), \ INCLUDE_FILES := $(GENSRC_UC_SRC_FILE), \ TOOLCHAIN := TOOLCHAIN_BUILD, \ @@ -124,7 +124,7 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) SOL_COPYRIGHT_YEARS = $(shell $(CAT) $(GENSRC_SOL_SRC)/$(GENSRC_SOL_SRC_FILE) | \ $(NAWK) '/^.*Copyright.*Oracle/ { printf "%s %s",$$4,$$5 }') - $(eval $(call SetupNativeCompilation,BUILD_GENSRC_SOL_EXE, \ + $(eval $(call SetupNativeCompilation, BUILD_GENSRC_SOL_EXE, \ SRC := $(GENSRC_SOL_SRC), \ INCLUDE_FILES := $(GENSRC_SOL_SRC_FILE), \ TOOLCHAIN := TOOLCHAIN_BUILD, \ diff --git a/jdk/make/gensrc/GensrcProperties.gmk b/jdk/make/gensrc/GensrcProperties.gmk index 2cc6231175e..7293a19bbeb 100644 --- a/jdk/make/gensrc/GensrcProperties.gmk +++ b/jdk/make/gensrc/GensrcProperties.gmk @@ -75,7 +75,7 @@ define SetupCompilePropertiesBody # Convert .../src//share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties # to .../support/gensrc//com/sun/tools/javac/resources/javac_zh_CN.java - # Strip away prefix and suffix, leaving for example only: + # Strip away prefix and suffix, leaving for example only: # "/share/classes/com/sun/tools/javac/resources/javac_zh_CN" $1_JAVAS := $$(patsubst $$($1_MODULE_PATH_ROOT)/%, \ $(SUPPORT_OUTPUTDIR)/gensrc/%, \ diff --git a/jdk/make/gensrc/GensrcSwing.gmk b/jdk/make/gensrc/GensrcSwing.gmk index 2f643d4abc2..eee0c044f2f 100644 --- a/jdk/make/gensrc/GensrcSwing.gmk +++ b/jdk/make/gensrc/GensrcSwing.gmk @@ -31,12 +31,11 @@ NIMBUS_GENSRC_DIR = $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/javax/swing/plaf/ni NIMBUS_SKIN_FILE = $(JDK_TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/_the.generated_nimbus: $(NIMBUS_SKIN_FILE) $(BUILD_TOOLS_JDK) + $(call LogInfo, Generating Nimbus source files) $(MKDIR) -p $(@D) - $(ECHO) "Generating Nimbus source files" - $(TOOL_GENERATENIMBUS) $(LOG_INFO) \ + $(TOOL_GENERATENIMBUS) $(LOG_DEBUG) \ -skinFile $(NIMBUS_SKIN_FILE) -buildDir $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop \ -packagePrefix $(NIMBUS_PACKAGE).nimbus -lafName Nimbus - $(ECHO) $(LOG_INFO) "Finished generating Nimbus source files" $(TOUCH) $@ GENSRC_SWING_NIMBUS := $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/_the.generated_nimbus diff --git a/jdk/make/gensrc/GensrcX11Wrappers.gmk b/jdk/make/gensrc/GensrcX11Wrappers.gmk index b9823c36be5..e4e3bba5745 100644 --- a/jdk/make/gensrc/GensrcX11Wrappers.gmk +++ b/jdk/make/gensrc/GensrcX11Wrappers.gmk @@ -63,14 +63,14 @@ GENSRC_X11_SIZES_USED := $(addprefix $(GENSRC_X11WRAPPERS_TMP)/sizes., $(GENSRC_ # Copy only the sizes.* files that are actually needed. WrapperGenerator picks up any it finds from the # file prefix it is given so those not needed need to be hidden. $(GENSRC_X11WRAPPERS_TMP)/sizes.%: $(GENSRC_SIZER_DIR)/sizes.% - $(MKDIR) -p $(@D) + $(call MakeDir, $(@D)) $(RM) '$@' $(SORT) $< > $@ # Run the tool on the offset files copied from the source repository to generate several Java classes # used in awt. $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/_the.generated.x11: $(GENSRC_X11_SIZES_USED) $(BUILD_TOOLS_JDK) - $(MKDIR) -p $(GENSRC_X11WRAPPERS_DST) + $(call MakeDir, $(GENSRC_X11WRAPPERS_DST)) $(TOOL_WRAPPERGENERATOR) $(GENSRC_X11WRAPPERS_DST) $(GENSRC_SIZER_DIR)/xlibtypes.txt "gen" $(GENSRC_X11WRAPPERS_TMP)/sizes $(TOUCH) $@ @@ -82,8 +82,8 @@ ifneq ($(COMPILE_TYPE), cross) # Generate the C code for the program that will output the offset file. $(GENSRC_X11WRAPPERS_TMP)/sizer.%.c: $(GENSRC_SIZER_DIR)/xlibtypes.txt $(BUILD_TOOLS_JDK) - $(ECHO) "Generating X11 wrapper ($*-bit version)" - $(MKDIR) -p $(@D) + $(call LogInfo, Generating X11 wrapper ($*-bit version)) + $(call MakeDir, $(@D)) $(TOOL_WRAPPERGENERATOR) $(@D) $(GENSRC_SIZER_DIR)/xlibtypes.txt "sizer" $* # use -m32/-m64 only if the compiler supports it @@ -103,7 +103,7 @@ ifneq ($(COMPILE_TYPE), cross) # Compile the C code into an executable. $(GENSRC_X11WRAPPERS_TMP)/sizer.%.exe: $(GENSRC_X11WRAPPERS_TMP)/sizer.%.c - $(MKDIR) -p $(@D) + $(call MakeDir, $(@D)) (cd $(@D) && $(CC) $(MEMORY_MODEL_FLAG) -o $@ $< \ $(X_CFLAGS) \ $(X_LIBS) \ @@ -114,9 +114,9 @@ ifneq ($(COMPILE_TYPE), cross) # Run the executable create the offset file and check that it is identical # to the offset file in the source code repository. $(GENSRC_X11WRAPPERS_TMP)/sizes.%.verification: $(GENSRC_X11WRAPPERS_TMP)/sizer.%.exe - $(MKDIR) -p $(@D) + $(call LogInfo, Verifying X11 wrapper sizes) + $(call MakeDir, $(@D)) $(GENSRC_X11WRAPPERS_TMP)/sizer.$*.exe | $(SORT) > $@.tmp - $(ECHO) Verifying $(GENSRC_X11WRAPPERS_TMP)/sizes.$*.verification.tmp to $(GENSRC_X11WRAPPERS_TMP)/sizes.$* $(DIFF) $(GENSRC_X11WRAPPERS_TMP)/sizes.$*.verification.tmp $(GENSRC_X11WRAPPERS_TMP)/sizes.$* mv $@.tmp $@ diff --git a/jdk/make/launcher/LauncherCommon.gmk b/jdk/make/launcher/LauncherCommon.gmk index aeee54a2d0a..701b2a962e3 100644 --- a/jdk/make/launcher/LauncherCommon.gmk +++ b/jdk/make/launcher/LauncherCommon.gmk @@ -31,9 +31,6 @@ ifeq ($(OPENJDK_TARGET_OS), macosx) ENABLE_DEBUG_SYMBOLS := false endif -# Prepare the find cache. -$(eval $(call FillCacheFind, $(JDK_TOPDIR)/src/java.base/share/native/launcher)) - ifeq ($(OPENJDK_TARGET_OS), macosx) ORIGIN_ARG := $(call SET_EXECUTABLE_ORIGIN) else @@ -124,7 +121,7 @@ define SetupBuildLauncherBody $1_LDFLAGS += -exported_symbols_list \ $(SUPPORT_OUTPUTDIR)/build-static/exported.symbols $1_LIBS += \ - $(shell $(FIND) $(SUPPORT_OUTPUTDIR)/modules_libs/java.base -name "*.a") \ + $$(shell $(FIND) $(SUPPORT_OUTPUTDIR)/modules_libs/java.base -name "*.a") \ $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/libdt_socket.a \ $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/libjdwp.a \ $(SUPPORT_OUTPUTDIR)/native/java.base/$(LIBRARY_PREFIX)fdlibm$(STATIC_LIBRARY_SUFFIX) \ @@ -174,8 +171,7 @@ define SetupBuildLauncherBody endif $$(eval $$(call SetupNativeCompilation, BUILD_LAUNCHER_$1, \ - SRC := $(LAUNCHER_SRC), \ - INCLUDE_FILES := main.c, \ + EXTRA_FILES := $(LAUNCHER_SRC)/main.c, \ OPTIMIZATION := $$($1_OPTIMIZATION), \ CFLAGS := $$($1_CFLAGS) \ $(LAUNCHER_CFLAGS) \ diff --git a/jdk/make/lib/Awt2dLibraries.gmk b/jdk/make/lib/Awt2dLibraries.gmk index 08cd4d774ab..395521c5da8 100644 --- a/jdk/make/lib/Awt2dLibraries.gmk +++ b/jdk/make/lib/Awt2dLibraries.gmk @@ -750,7 +750,8 @@ ifeq ($(OPENJDK_TARGET_OS), windows) $(BUILD_LIBJAWT): $(BUILD_LIBAWT) $(JDK_OUTPUTDIR)/lib/$(LIBRARY_PREFIX)jawt$(STATIC_LIBRARY_SUFFIX): $(BUILD_LIBJAWT) - $(ECHO) Copying $(@F) + $(call LogInfo, Copying $(patsubst $(OUTPUT_ROOT)/%, %, $@)) + $(call MakeDir, $(@D)) $(CP) $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjawt/$(LIBRARY_PREFIX)jawt$(STATIC_LIBRARY_SUFFIX) $@ TARGETS += $(JDK_OUTPUTDIR)/lib/$(LIBRARY_PREFIX)jawt$(STATIC_LIBRARY_SUFFIX) diff --git a/jdk/make/lib/Lib-java.base.gmk b/jdk/make/lib/Lib-java.base.gmk index 0699a42dd34..345fda65908 100644 --- a/jdk/make/lib/Lib-java.base.gmk +++ b/jdk/make/lib/Lib-java.base.gmk @@ -49,7 +49,7 @@ ifeq ($(STATIC_BUILD), true) JAVA_BASE_EXPORT_SYMBOL_FILE := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/java.base.symbols $(JAVA_BASE_EXPORT_SYMBOL_FILE): $(JAVA_BASE_EXPORT_SYMBOLS_SRC) - $(ECHO) $(LOG_INFO) "Generating java.base.symbols file" + $(call LogInfo, Generating java.base.symbols file) $(CAT) $^ > $@ # The individual symbol files is generated when the respective lib is built diff --git a/jdk/make/lib/Lib-jdk.jdwp.agent.gmk b/jdk/make/lib/Lib-jdk.jdwp.agent.gmk index 14784d3796a..d64b395c163 100644 --- a/jdk/make/lib/Lib-jdk.jdwp.agent.gmk +++ b/jdk/make/lib/Lib-jdk.jdwp.agent.gmk @@ -111,7 +111,7 @@ ifeq ($(STATIC_BUILD), true) JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE := $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/jdk.jdwp.agent.symbols $(JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE): $(JDK_JDWP_AGENT_EXPORT_SYMBOLS_SRC) - $(ECHO) $(LOG_INFO) "Generating jdk.jdwp.agent symbols file" + $(call LogInfo, Generating jdk.jdwp.agent symbols file) $(CAT) $^ > $@ # The individual symbol files is generated when the respective lib is built diff --git a/jdk/make/lib/LibCommon.gmk b/jdk/make/lib/LibCommon.gmk index c716b48d430..b341eac9326 100644 --- a/jdk/make/lib/LibCommon.gmk +++ b/jdk/make/lib/LibCommon.gmk @@ -23,8 +23,6 @@ # questions. # -include $(SPEC) -include MakeBase.gmk include NativeCompilation.gmk # Hook to include the corresponding custom file, if present. @@ -92,3 +90,5 @@ ifeq ($(USE_EXTERNAL_LIBZ), true) else ZLIB_CPPFLAGS := -I$(JDK_TOPDIR)/src/java.base/share/native/libzip/zlib-1.2.8 endif + +############################################################################### diff --git a/jdk/src/java.base/share/classes/java/net/SocketImpl.java b/jdk/src/java.base/share/classes/java/net/SocketImpl.java index 600c68457af..b4b9c1900c7 100644 --- a/jdk/src/java.base/share/classes/java/net/SocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/SocketImpl.java @@ -376,19 +376,23 @@ public abstract class SocketImpl implements SocketOptions { * @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 @@ public abstract class SocketImpl implements SocketOptions { */ @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 --git a/jdk/src/java.base/share/classes/java/util/Locale.java b/jdk/src/java.base/share/classes/java/util/Locale.java index 25697ca0c9d..2d121e2e7ef 100644 --- a/jdk/src/java.base/share/classes/java/util/Locale.java +++ b/jdk/src/java.base/share/classes/java/util/Locale.java @@ -3144,6 +3144,18 @@ public final class Locale implements Cloneable, Serializable { && 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 --git a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java index c8885841ada..31715d40c82 100644 --- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java +++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java @@ -47,6 +47,9 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl 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 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl 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 --git a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java index d07c90da5af..272130bd6b9 100644 --- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java @@ -61,6 +61,9 @@ class PlainSocketImpl extends AbstractPlainSocketImpl 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 @@ class PlainSocketImpl extends AbstractPlainSocketImpl 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 --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index b62eeb51377..fbe25e8224f 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -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,7 +31,8 @@ tier1 = \ -java/util/zip/TestLocalTime.java \ :jdk_util \ -java/util/WeakHashMap/GCDuringIteration.java \ - -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.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 \ @@ -42,6 +43,7 @@ tier2 = \ java/util/zip/TestLocalTime.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 \ diff --git a/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java b/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java new file mode 100644 index 00000000000..074f7644b9d --- /dev/null +++ b/jdk/test/java/net/SocketOption/UnsupportedOptionsTest.java @@ -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 --git a/jdk/test/java/nio/channels/ServerSocketChannel/AdaptServerSocket.java b/jdk/test/java/nio/channels/ServerSocketChannel/AdaptServerSocket.java index 13aeea1bba4..79391ecca99 100644 --- a/jdk/test/java/nio/channels/ServerSocketChannel/AdaptServerSocket.java +++ b/jdk/test/java/nio/channels/ServerSocketChannel/AdaptServerSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,8 @@ */ /* @test + * @bug 4286936 8146213 * @summary Unit test for server-socket-channel adaptors - * @key intermittent */ import java.io.*; @@ -77,6 +77,9 @@ public class AdaptServerSocket { static void test(int clientDally, int timeout, boolean shouldTimeout) throws Exception { + boolean needClient = !shouldTimeout; + client = null; + clientException = null; clientStarted = false; out.println(); @@ -90,9 +93,11 @@ public class AdaptServerSocket { sso.bind(null); out.println("bound: " + ssc); out.println(" " + sso); - startClient(sso.getLocalPort(), clientDally); - while (!clientStarted) { - Thread.sleep(20); + if (needClient) { + startClient(sso.getLocalPort(), clientDally); + while (!clientStarted) { + Thread.sleep(20); + } } Socket so = null; try { @@ -115,10 +120,12 @@ public class AdaptServerSocket { out.println("server: read " + b); } } - client.interrupt(); - client.join(); - if (clientException != null) - throw clientException; + if (needClient) { + client.interrupt(); + client.join(); + if (clientException != null) + throw clientException; + } } public static void main(String[] args) throws Exception { diff --git a/jdk/test/java/nio/channels/ServerSocketChannel/Basic.java b/jdk/test/java/nio/channels/ServerSocketChannel/Basic.java index be30778759f..d821d28a89d 100644 --- a/jdk/test/java/nio/channels/ServerSocketChannel/Basic.java +++ b/jdk/test/java/nio/channels/ServerSocketChannel/Basic.java @@ -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 @@ public class Basic { 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 --git a/jdk/test/java/nio/channels/ServerSocketChannel/NonBlockingAccept.java b/jdk/test/java/nio/channels/ServerSocketChannel/NonBlockingAccept.java index 1b985e8c68a..a210402903a 100644 --- a/jdk/test/java/nio/channels/ServerSocketChannel/NonBlockingAccept.java +++ b/jdk/test/java/nio/channels/ServerSocketChannel/NonBlockingAccept.java @@ -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 @@ public class NonBlockingAccept { 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 --git a/jdk/test/java/util/Locale/Bug8026766.java b/jdk/test/java/util/Locale/Bug8026766.java new file mode 100644 index 00000000000..630737fdf99 --- /dev/null +++ b/jdk/test/java/util/Locale/Bug8026766.java @@ -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 --git a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java index 372febce6b8..c236bd231cc 100644 --- a/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java +++ b/jdk/test/java/util/concurrent/forkjoin/FJExceptionTableLeak.java @@ -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 --git a/jdk/test/javax/net/ssl/SSLSession/SSLCtxAccessToSessCtx.java b/jdk/test/javax/net/ssl/SSLSession/SSLCtxAccessToSessCtx.java index 14ed3eab716..95b9aae3512 100644 --- a/jdk/test/javax/net/ssl/SSLSession/SSLCtxAccessToSessCtx.java +++ b/jdk/test/javax/net/ssl/SSLSession/SSLCtxAccessToSessCtx.java @@ -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 @@ -35,6 +35,7 @@ import java.io.*; import java.net.*; import javax.net.ssl.*; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import java.security.KeyStore; public class SSLCtxAccessToSessCtx { @@ -63,7 +64,7 @@ public class SSLCtxAccessToSessCtx { /* * Is the server ready to serve? */ - volatile static boolean serverReady = false; + AtomicInteger serverReady = new AtomicInteger(1); // only one port now /* * Turn on SSL debugging? @@ -89,12 +90,13 @@ public class SSLCtxAccessToSessCtx { SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); - serverPorts[createdPorts++] = sslServerSocket.getLocalPort(); + int slot = createdPorts.getAndIncrement(); + serverPorts[slot] = sslServerSocket.getLocalPort(); /* * Signal Client, we're ready for his connect. */ - serverReady = true; + serverReady.getAndDecrement(); int read = 0; SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); InputStream sslIS = sslSocket.getInputStream(); @@ -121,7 +123,7 @@ public class SSLCtxAccessToSessCtx { /* * Wait for server to get started. */ - while (!serverReady) { + while (serverReady.get() > 0) { Thread.sleep(50); } /* @@ -151,8 +153,8 @@ public class SSLCtxAccessToSessCtx { * The remainder is just support stuff */ - volatile int serverPorts[] = new int[]{0}; - volatile int createdPorts = 0; + int serverPorts[] = new int[]{0}; // only one port at present + AtomicInteger createdPorts = new AtomicInteger(0); static SSLServerSocketFactory sslssf; static SSLSocketFactory sslsf; static SSLContext sslctx; @@ -255,14 +257,20 @@ public class SSLCtxAccessToSessCtx { */ System.err.println("Server died..."); e.printStackTrace(); - serverReady = true; + serverReady.set(0); serverException = e; } } }; serverThread.start(); } else { - doServerSide(port); + try { + doServerSide(port); + } catch (Exception e) { + serverException = e; + } finally { + serverReady.set(0); + } } } @@ -284,7 +292,11 @@ public class SSLCtxAccessToSessCtx { }; clientThread.start(); } else { - doClientSide(); + try { + doClientSide(); + } catch (Exception e) { + clientException = e; + } } } } diff --git a/jdk/test/javax/net/ssl/SSLSession/SessionTimeOutTests.java b/jdk/test/javax/net/ssl/SSLSession/SessionTimeOutTests.java index 05aa61df609..ce592fece7f 100644 --- a/jdk/test/javax/net/ssl/SSLSession/SessionTimeOutTests.java +++ b/jdk/test/javax/net/ssl/SSLSession/SessionTimeOutTests.java @@ -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 @@ -112,7 +112,8 @@ public class SessionTimeOutTests { SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(serverPort); - serverPorts[createdPorts++] = sslServerSocket.getLocalPort(); + int slot = createdPorts.getAndIncrement(); + serverPorts[slot] = sslServerSocket.getLocalPort(); /* * Signal Client, we're ready for his connect. @@ -288,8 +289,8 @@ public class SessionTimeOutTests { * The remainder is just support stuff */ - volatile int serverPorts[] = new int[PORTS]; - volatile int createdPorts = 0; + int serverPorts[] = new int[PORTS]; + AtomicInteger createdPorts = new AtomicInteger(0); static SSLServerSocketFactory sslssf; static SSLSocketFactory sslsf; static SSLContext sslctx; diff --git a/jdk/test/javax/security/auth/SubjectDomainCombiner/Optimize.java b/jdk/test/javax/security/auth/SubjectDomainCombiner/Optimize.java index 99ec943caaf..df5adef42a6 100644 --- a/jdk/test/javax/security/auth/SubjectDomainCombiner/Optimize.java +++ b/jdk/test/javax/security/auth/SubjectDomainCombiner/Optimize.java @@ -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 @@ public class Optimize { 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 --git a/jdk/test/javax/xml/ws/publish/WSTest.java b/jdk/test/javax/xml/ws/publish/WSTest.java new file mode 100644 index 00000000000..539f2d4b53b --- /dev/null +++ b/jdk/test/javax/xml/ws/publish/WSTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8146086 + * @summary Publishing two webservices on same port fails with "java.net.BindException: Address already in use" + * @run main/othervm WSTest + */ +import javax.jws.WebMethod; +import javax.jws.WebService; +import javax.xml.ws.Endpoint; +import java.net.ServerSocket; + +public class WSTest { + + @WebService(targetNamespace = "test") + public static class Method1 { + @WebMethod + public String getMethod1Value() { + return "from Method1"; + } + } + + @WebService(targetNamespace = "test") + public static class Method2 { + @WebMethod + public String getMethod2Value() { + return "from Method2"; + } + } + + public static void main(String[] args) throws Exception { + + // find a free port + ServerSocket ss = new ServerSocket(0); + int port = ss.getLocalPort(); + ss.close(); + + Endpoint endPoint1 = null; + Endpoint endPoint2 = null; + try { + endPoint1 = Endpoint.publish("http://0.0.0.0:" + port + "/method1", + new Method1()); + endPoint2 = Endpoint.publish("http://0.0.0.0:" + port + "/method2", + new Method2()); + + System.out.println("Sleep 3 secs..."); + + Thread.sleep(3000); + } finally { + stop(endPoint2); + stop(endPoint1); + } + } + + private static void stop(Endpoint endPoint) { + if (endPoint == null) return; + + try { + endPoint.stop(); + } catch (Throwable ignored) { + } + } + +} diff --git a/langtools/.hgtags b/langtools/.hgtags index 0d8509b1d1f..f116222c244 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -343,3 +343,4 @@ ae8cdc734bab4f19ef8babd2434dcf024672ad38 jdk-9+97 345520da2ec17100cb512a53d541a307a195305e jdk-9+98 cb73b474703e2de266542b505cffd658bcc052da jdk-9+99 51136404ee5e6cd5868b60d66ebd55a02170b508 jdk-9+100 +3b3bea483542bc08278af529fb25f2e5930da945 jdk-9+101 diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index 590ca4377c0..33029b46497 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -1146,14 +1146,21 @@ public class Types { 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 557b921e20f..b5dfb11dc42 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -1137,7 +1137,56 @@ public class Resolve { /** 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 @@ public class Resolve { * 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 { + class MostSpecificFunctionReturnChecker extends DeferredAttr.PolyScanner { - final Type t; - final Type s; + 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 @@ public class Resolve { @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 @@ public class Resolve { @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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index ba68b58457a..28be92d14df 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -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 @@ public class JavaTokenizer { } /** 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 @@ public class JavaTokenizer { 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 @@ public class JavaTokenizer { 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 @@ public class JavaTokenizer { } 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java index cc54eb57e2a..b288955b9a1 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Source.java @@ -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 @@ public class Source implements Comparable { 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 @@ public class Source implements Comparable { 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 @@ public class Source implements Comparable { suffix = ""; } file = f; - root = r; lastModified = f.lastModified(); linkedOnly = false; } @@ -102,7 +108,6 @@ public class Source implements Comparable { suffix = ""; } file = null; - root = null; lastModified = lm; linkedOnly = false; int ls = n.lastIndexOf('/'); @@ -112,7 +117,6 @@ public class Source implements Comparable { 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 @@ public class Source implements Comparable { */ 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; - 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); + if (root == null) + return; - 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); - } + FileSystem fs = root.toPath().getFileSystem(); + + if (includes.isEmpty()) { + includes = Collections.singletonList("**"); } - } - /** - * 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) { + List includeMatchers = createPathMatchers(fs, includes); + List excludeMatchers = createPathMatchers(fs, excludes); - // Convert Windows '\' to '/' for the sake of comparing with the patterns - path = path.replace(File.separatorChar, '/'); + Files.walkFileTree(root.toPath(), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - for (String p : patterns) { - // Exact match - if (p.equals(path)) - return true; + Path relToRoot = root.toPath().relativize(file); - // 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; + 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()); } - } - } - } - return false; - } + existing = currentModule.lookupSource(file.toString()); + if (existing != null) { - /** - * 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, '/'); + // 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()); + } - 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()); + + ////////////////////////////////////////////////////////////// + // 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); + ////////////////////////////////////////////////////////////// } } - 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); + + return FileVisitResult.CONTINUE; } - } - return currentModule; + }); } - 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); + 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 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); + } + + @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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java index 5d137ef8be7..03fcc537244 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/Util.java @@ -230,4 +230,10 @@ public class Util { 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java index 092501b483b..5a6194acb8e 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/SjavacImpl.java @@ -144,77 +144,77 @@ public class SjavacImpl implements Sjavac { 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<>(); - - // 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; - } - - - // 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); - - // 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); - - // 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(); - - // 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 { + // 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); + + 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<>(); + + 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); + + 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); + + // 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(); + // Check recorded classpath public apis. Taint packages that depend on // classpath classes whose public apis have changed. javac_state.taintPackagesDependingOnChangedClasspathPackages(); @@ -229,8 +229,16 @@ public class SjavacImpl implements Sjavac { // (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 @@ public class SjavacImpl implements Sjavac { 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 @@ public class SjavacImpl implements Sjavac { Map foundModules, Module currentModule, boolean permitSourcesInDefaultPackage, - boolean inLinksrc) { + boolean inLinksrc) + throws IOException { for (SourceLocation source : sourceLocations) { source.findSourceFiles(sourceTypes, diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java index 364c48b4117..d64d3182cc0 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java @@ -93,7 +93,7 @@ public enum Option { 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 @@ public enum Option { 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 @@ public enum Option { 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 @@ public enum Option { 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/OptionHelper.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/OptionHelper.java index 7f3304a4008..709bf835a5b 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/OptionHelper.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/OptionHelper.java @@ -53,12 +53,6 @@ public abstract class OptionHelper { /** 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Options.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Options.java index 6b4fbf7ef98..61d1ec13545 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Options.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Options.java @@ -220,8 +220,6 @@ public class Options { 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()); } } @@ -379,18 +377,6 @@ public class Options { includes.add(inclPattern); } - @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)) { @@ -519,9 +505,7 @@ public class Options { result.add(new SourceLocation( path, includes, - excludes, - includeFiles, - excludeFiles)); + excludes)); } resetFilters(); return result; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/SourceLocation.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/SourceLocation.java index ecc5b96c8c6..2b6b12c27f5 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/SourceLocation.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/SourceLocation.java @@ -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 @@ public class SourceLocation { 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 @@ public class SourceLocation { 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 @@ public class SourceLocation { 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java index 3d5f1952b43..c66730a928b 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/PortFile.java @@ -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 @@ public class PortFile { /** * 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 --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java index 1e506ac5275..1f9ec7504d4 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/server/SjavacServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -279,7 +279,7 @@ public class SjavacServer implements Terminable { // failed connection attempts try { portFile.delete(); - } catch (IOException e) { + } catch (IOException | InterruptedException e) { e.printStackTrace(theLog); } try { diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java index 17743cd7166..487215ca4a0 100644 --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/util/VisibleMemberMap.java @@ -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 @@ public class VisibleMemberMap { 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java index bbebbfe2077..5ac073b1b9a 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/remote/RemoteAgent.java @@ -28,6 +28,9 @@ import java.io.File; 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.net.Socket; 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 @@ class RemoteAgent { 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 @@ class RemoteAgent { } 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index a66d9cbc1aa..180fc4d8206 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -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.MissingResourceException; 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 @@ public class JShellTool { 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 @@ public class JShellTool { 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 @@ public class JShellTool { "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 @@ public class JShellTool { 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 @@ public class JShellTool { 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 @@ public class JShellTool { 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 @@ public class JShellTool { state.addToClasspath(cmdlineClasspath); } - String start; if (cmdlineStartup == null) { start = PREFS.get(STARTUP_KEY, ""); @@ -431,7 +453,7 @@ public class JShellTool { String incomplete = ""; while (live) { String prompt; - if (in.interactiveOutput() && displayPrompt) { + if (displayPrompt) { prompt = testPrompt ? incomplete.isEmpty() ? "\u0005" //ENQ @@ -480,6 +502,12 @@ public class JShellTool { } } + private void addToReplayHistory(String s) { + if (currentNameSpace == mainNamespace) { + replayableHistory.add(s); + } + } + private String processSourceCatchingReset(String src) { try { input.beforeUserCode(); @@ -516,7 +544,12 @@ public class JShellTool { 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 class JShellTool { 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 @@ public class JShellTool { enum CommandKind { NORMAL, + REPLAY, HIDDEN, HELP_ONLY; } @@ -602,6 +636,7 @@ public class JShellTool { 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 @@ public class JShellTool { }; } + 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 @@ public class JShellTool { 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 @@ public class JShellTool { 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 @@ public class JShellTool { 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 @@ public class JShellTool { // --- 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 @@ public class JShellTool { 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 @@ public class JShellTool { 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 @@ public class JShellTool { 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 @@ public class JShellTool { } } - 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 @@ public class JShellTool { 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 @@ public class JShellTool { } else { ExternalEditor.edit(editor, errorHandler, src, saveHandler, input); } + return true; } //where // receives editor requests to save @@ -1135,10 +1200,9 @@ public class JShellTool { } } - 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 @@ public class JShellTool { } 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 @@ public class JShellTool { } 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 void cmdReset() { + private boolean cmdReset() { live = false; fluff("Resetting state."); + return true; } - private void cmdSave(String arg_filename) { + 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 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 @@ public class JShellTool { 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 @@ public class JShellTool { } } 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 @@ public class JShellTool { 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 @@ public class JShellTool { } 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 @@ public class JShellTool { 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 @@ public class JShellTool { } } - 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 @@ public class JShellTool { 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 @@ public class JShellTool { } } -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 @@ -1816,11 +1921,6 @@ class ScannerIOContext extends IOContext { return Collections.emptyList(); } - @Override - public void close() { - scannerIn.close(); - } - @Override public boolean terminalEditorRunning() { return false; @@ -1847,19 +1947,62 @@ class ScannerIOContext extends IOContext { } } -class FileScannerIOContext extends ScannerIOContext { +class ScannerIOContext extends NonInteractiveIOContext { + private final Scanner scannerIn; - public FileScannerIOContext(String fn) throws FileNotFoundException { - this(new FileReader(fn)); - } - - public FileScannerIOContext(Reader rdr) throws FileNotFoundException { - super(new Scanner(rdr), null); + ScannerIOContext(Scanner scannerIn) { + this.scannerIn = scannerIn; } @Override - public boolean interactiveOutput() { - return false; + 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 { + + FileScannerIOContext(String fn) throws FileNotFoundException { + this(new FileReader(fn)); + } + + 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 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java index 6e6b02ae9b9..ad115656661 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java @@ -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 @@ class ExecutionControl { 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 @@ class ExecutionControl { 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 @@ class ExecutionControl { } } } + + 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java index d1a68130c67..56cf4d95f9d 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JDIConnection.java @@ -133,7 +133,7 @@ class JDIConnection { 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 @@ class JDIConnection { } } - boolean isOpen() { + synchronized boolean isOpen() { return (vm != null); } @@ -173,13 +173,17 @@ class JDIConnection { 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java index 8892b54c964..89e2463f4a8 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/OuterWrap.java @@ -182,9 +182,9 @@ final class OuterWrap implements GeneralWrap { return null; } - @Override - public String toString() { - return "WrappedDiagnostic(" + getMessage(null) + ":" + getPosition() + ")"; - } + @Override + public String toString() { + return "WrappedDiagnostic(" + getMessage(null) + ":" + getPosition() + ")"; + } } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index 93f52e2e93b..0582fd66cae 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -33,7 +33,6 @@ import com.sun.tools.javac.api.JavacTool; 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 @@ class TaskFactory { 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 @@ class TaskFactory { 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 @@ class TaskFactory { 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java index 6233afe12fa..774f25663a1 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java @@ -50,6 +50,7 @@ import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; 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 @@ final class Unit { 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 --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java index 9ee8a826dbb..8cc42150790 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Util.java @@ -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 @@ class Util { 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 --git a/langtools/test/jdk/jshell/ReplToolTesting.java b/langtools/test/jdk/jshell/ReplToolTesting.java index a4d1fab3f21..05dd5389e0b 100644 --- a/langtools/test/jdk/jshell/ReplToolTesting.java +++ b/langtools/test/jdk/jshell/ReplToolTesting.java @@ -152,13 +152,13 @@ public class ReplToolTesting { } 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 class ReplToolTesting { } 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 @@ public class ReplToolTesting { } } + 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 --git a/langtools/test/jdk/jshell/T8146368/JShellTest8146368.java b/langtools/test/jdk/jshell/T8146368/JShellTest8146368.java new file mode 100644 index 00000000000..8cf92545bb5 --- /dev/null +++ b/langtools/test/jdk/jshell/T8146368/JShellTest8146368.java @@ -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 --git a/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java b/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java new file mode 100644 index 00000000000..3e3273add7c --- /dev/null +++ b/langtools/test/jdk/jshell/T8146368/JShellToolTest8146368.java @@ -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 --git a/langtools/test/jdk/jshell/ToolBasicTest.java b/langtools/test/jdk/jshell/ToolBasicTest.java index 03c0e29d9af..eff362d7f1f 100644 --- a/langtools/test/jdk/jshell/ToolBasicTest.java +++ b/langtools/test/jdk/jshell/ToolBasicTest.java @@ -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 @@ public class ToolBasicTest extends ReplToolTesting { 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 @@ public class ToolBasicTest extends ReplToolTesting { 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 @@ public class ToolBasicTest extends ReplToolTesting { ); } + 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 --git a/langtools/test/jdk/jshell/ToolReloadTest.java b/langtools/test/jdk/jshell/ToolReloadTest.java new file mode 100644 index 00000000000..0d41b1aa922 --- /dev/null +++ b/langtools/test/jdk/jshell/ToolReloadTest.java @@ -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 --git a/langtools/test/tools/javac/BadHexConstant.java b/langtools/test/tools/javac/BadHexConstant.java index b9f88f1ccf4..c88bff561a1 100644 --- a/langtools/test/tools/javac/BadHexConstant.java +++ b/langtools/test/tools/javac/BadHexConstant.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 4049982 + * @bug 4049982 8056897 * @summary Compiler permitted invalid hex literal. * @author turnidge * diff --git a/langtools/test/tools/javac/BadHexConstant.out b/langtools/test/tools/javac/BadHexConstant.out index e73e871e96c..cda08f8761a 100644 --- a/langtools/test/tools/javac/BadHexConstant.out +++ b/langtools/test/tools/javac/BadHexConstant.out @@ -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 --git a/langtools/test/tools/javac/api/T6430241.java b/langtools/test/tools/javac/api/T6430241.java deleted file mode 100644 index c607d8bfee0..00000000000 --- a/langtools/test/tools/javac/api/T6430241.java +++ /dev/null @@ -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 --git a/langtools/test/tools/javac/diags/examples/IdentifierExpected.java b/langtools/test/tools/javac/diags/examples/IdentifierExpected.java index f36b8ad2161..fd79267f00d 100644 --- a/langtools/test/tools/javac/diags/examples/IdentifierExpected.java +++ b/langtools/test/tools/javac/diags/examples/IdentifierExpected.java @@ -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 --git a/langtools/test/tools/javac/file/BootClassPathPrepend.java b/langtools/test/tools/javac/file/BootClassPathPrepend.java deleted file mode 100644 index 9bd38b61715..00000000000 --- a/langtools/test/tools/javac/file/BootClassPathPrepend.java +++ /dev/null @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific15.java b/langtools/test/tools/javac/lambda/MostSpecific15.java new file mode 100644 index 00000000000..1c2db64c9a3 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific15.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific16.java b/langtools/test/tools/javac/lambda/MostSpecific16.java new file mode 100644 index 00000000000..c3ed651b7ec --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific16.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific16.out b/langtools/test/tools/javac/lambda/MostSpecific16.out new file mode 100644 index 00000000000..f80856c1f7f --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific16.out @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific17.java b/langtools/test/tools/javac/lambda/MostSpecific17.java new file mode 100644 index 00000000000..907c00d9bd4 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific17.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific18.java b/langtools/test/tools/javac/lambda/MostSpecific18.java new file mode 100644 index 00000000000..40536982de8 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific18.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific19.java b/langtools/test/tools/javac/lambda/MostSpecific19.java new file mode 100644 index 00000000000..6f600e02fd4 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific19.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific19.out b/langtools/test/tools/javac/lambda/MostSpecific19.out new file mode 100644 index 00000000000..90a824febee --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific19.out @@ -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 --git a/nashorn/test/src/jdk/internal/dynalink/beans/test/CallerSensitiveTest.java b/langtools/test/tools/javac/lambda/MostSpecific20.java similarity index 60% rename from nashorn/test/src/jdk/internal/dynalink/beans/test/CallerSensitiveTest.java rename to langtools/test/tools/javac/lambda/MostSpecific20.java index a23404bed0a..3b5d56e3e52 100644 --- a/nashorn/test/src/jdk/internal/dynalink/beans/test/CallerSensitiveTest.java +++ b/langtools/test/tools/javac/lambda/MostSpecific20.java @@ -1,12 +1,10 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * 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. + * 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 @@ -23,16 +21,23 @@ * questions. */ -package jdk.internal.dynalink.beans.test; +/* + * @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); } -import jdk.dynalink.beans.BeansLinker; -import jdk.nashorn.test.models.ClassLoaderAware; -import org.testng.annotations.Test; + static void m1(F1 f) {} + static void m1(F2 f) {} -@SuppressWarnings("javadoc") -public class CallerSensitiveTest { - @Test - public void testCallerSensitive() { - BeansLinker.getLinkerForClass(ClassLoaderAware.class); + static String foo(Object in) { return "a"; } + + void test() { + m1(MostSpecific20::foo); } -} + +} \ No newline at end of file diff --git a/langtools/test/tools/javac/lambda/MostSpecific21.java b/langtools/test/tools/javac/lambda/MostSpecific21.java new file mode 100644 index 00000000000..e86c39adf34 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific21.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific21.out b/langtools/test/tools/javac/lambda/MostSpecific21.out new file mode 100644 index 00000000000..8ed90048b33 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific21.out @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific22.java b/langtools/test/tools/javac/lambda/MostSpecific22.java new file mode 100644 index 00000000000..5c56f8546e2 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific22.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific23.java b/langtools/test/tools/javac/lambda/MostSpecific23.java new file mode 100644 index 00000000000..796344ab4ad --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific23.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific23.out b/langtools/test/tools/javac/lambda/MostSpecific23.out new file mode 100644 index 00000000000..2e53c137d59 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific23.out @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific24.java b/langtools/test/tools/javac/lambda/MostSpecific24.java new file mode 100644 index 00000000000..f073e8ce966 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific24.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific24.out b/langtools/test/tools/javac/lambda/MostSpecific24.out new file mode 100644 index 00000000000..0f0b0afd85c --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific24.out @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific25.java b/langtools/test/tools/javac/lambda/MostSpecific25.java new file mode 100644 index 00000000000..1aeab2e1460 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific25.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific25.out b/langtools/test/tools/javac/lambda/MostSpecific25.out new file mode 100644 index 00000000000..e8568590db8 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific25.out @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific26.java b/langtools/test/tools/javac/lambda/MostSpecific26.java new file mode 100644 index 00000000000..f4bfd5240dd --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific26.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific26.out b/langtools/test/tools/javac/lambda/MostSpecific26.out new file mode 100644 index 00000000000..3f39d392e81 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific26.out @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific27.java b/langtools/test/tools/javac/lambda/MostSpecific27.java new file mode 100644 index 00000000000..2c758b2b3e4 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific27.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific28.java b/langtools/test/tools/javac/lambda/MostSpecific28.java new file mode 100644 index 00000000000..417adf03bcb --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific28.java @@ -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 --git a/langtools/test/tools/javac/lambda/MostSpecific28.out b/langtools/test/tools/javac/lambda/MostSpecific28.out new file mode 100644 index 00000000000..f3097b7fc40 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MostSpecific28.out @@ -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 --git a/langtools/test/tools/javac/lexer/JavaLexerTest.java b/langtools/test/tools/javac/lexer/JavaLexerTest.java new file mode 100644 index 00000000000..caa4c140d12 --- /dev/null +++ b/langtools/test/tools/javac/lexer/JavaLexerTest.java @@ -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 --git a/langtools/test/tools/javac/literals/T6891079.java b/langtools/test/tools/javac/literals/T6891079.java index 8d5edbcf71a..b454d20cc8a 100644 --- a/langtools/test/tools/javac/literals/T6891079.java +++ b/langtools/test/tools/javac/literals/T6891079.java @@ -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 --git a/langtools/test/tools/javac/literals/T6891079.out b/langtools/test/tools/javac/literals/T6891079.out index 4472d62bb7f..63aef8effc9 100644 --- a/langtools/test/tools/javac/literals/T6891079.out +++ b/langtools/test/tools/javac/literals/T6891079.out @@ -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 --git a/langtools/test/tools/sjavac/CompileExcludingDependency.java b/langtools/test/tools/sjavac/CompileExcludingDependency.java index 24174f1bfb3..cd650a83310 100644 --- a/langtools/test/tools/sjavac/CompileExcludingDependency.java +++ b/langtools/test/tools/sjavac/CompileExcludingDependency.java @@ -55,9 +55,9 @@ public class CompileExcludingDependency extends SJavacTester { 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 --git a/langtools/test/tools/sjavac/CompileWithAtFile.java b/langtools/test/tools/sjavac/CompileWithAtFile.java index 1107595cec8..580f8ae4aa8 100644 --- a/langtools/test/tools/sjavac/CompileWithAtFile.java +++ b/langtools/test/tools/sjavac/CompileWithAtFile.java @@ -47,8 +47,8 @@ public class CompileWithAtFile extends SJavacTester { 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 --git a/langtools/test/tools/sjavac/CompileWithInvisibleSources.java b/langtools/test/tools/sjavac/CompileWithInvisibleSources.java index 099b518217d..d39b4427988 100644 --- a/langtools/test/tools/sjavac/CompileWithInvisibleSources.java +++ b/langtools/test/tools/sjavac/CompileWithInvisibleSources.java @@ -64,7 +64,7 @@ public class CompileWithInvisibleSources extends SJavacTester { "package beta; public class B { }"); compile(GENSRC.toString(), - "-x", "beta", + "-x", "beta/*", "-sourcepath", GENSRC2.toString(), "-sourcepath", GENSRC3.toString(), "-d", BIN.toString(), diff --git a/langtools/test/tools/sjavac/CompileWithOverrideSources.java b/langtools/test/tools/sjavac/CompileWithOverrideSources.java index a010177e634..b3bc9a5d8bb 100644 --- a/langtools/test/tools/sjavac/CompileWithOverrideSources.java +++ b/langtools/test/tools/sjavac/CompileWithOverrideSources.java @@ -62,7 +62,7 @@ public class CompileWithOverrideSources extends SJavacTester { 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 --git a/langtools/test/tools/sjavac/ExclPattern.java b/langtools/test/tools/sjavac/ExclPattern.java deleted file mode 100644 index cd98da56082..00000000000 --- a/langtools/test/tools/sjavac/ExclPattern.java +++ /dev/null @@ -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 --git a/langtools/test/tools/sjavac/HiddenFiles.java b/langtools/test/tools/sjavac/HiddenFiles.java new file mode 100644 index 00000000000..32eead0de58 --- /dev/null +++ b/langtools/test/tools/sjavac/HiddenFiles.java @@ -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 --git a/langtools/test/tools/sjavac/IncludeExcludePatterns.java b/langtools/test/tools/sjavac/IncludeExcludePatterns.java new file mode 100644 index 00000000000..a263726ae84 --- /dev/null +++ b/langtools/test/tools/sjavac/IncludeExcludePatterns.java @@ -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 --git a/langtools/test/tools/sjavac/OptionDecoding.java b/langtools/test/tools/sjavac/OptionDecoding.java index 2ba5167b1fc..423b56b32ea 100644 --- a/langtools/test/tools/sjavac/OptionDecoding.java +++ b/langtools/test/tools/sjavac/OptionDecoding.java @@ -61,7 +61,6 @@ public class OptionDecoding { public static void main(String[] args) throws IOException { testPaths(); testDupPaths(); - testSourceLocations(); testSimpleOptions(); testServerConf(); testSearchPaths(); @@ -110,78 +109,6 @@ public class OptionDecoding { } } - // 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 @@ public class OptionDecoding { 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 --git a/langtools/test/tools/sjavac/Serialization.java b/langtools/test/tools/sjavac/Serialization.java index d8363622ea1..58d0cefd135 100644 --- a/langtools/test/tools/sjavac/Serialization.java +++ b/langtools/test/tools/sjavac/Serialization.java @@ -58,8 +58,6 @@ public class Serialization { 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 @@ public class Serialization { 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 --git a/langtools/test/tools/sjavac/util/OptionTestUtil.java b/langtools/test/tools/sjavac/util/OptionTestUtil.java index 54581005432..f751d6d4ad8 100644 --- a/langtools/test/tools/sjavac/util/OptionTestUtil.java +++ b/langtools/test/tools/sjavac/util/OptionTestUtil.java @@ -62,9 +62,7 @@ public class OptionTestUtil { 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 --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 7eb7a95a48e..c569557ec34 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -202,23 +202,28 @@ define SetupJavaCompilationBody # 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 @@ define SetupJavaCompilationBody $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 @@ define SetupJavaCompilationBody $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 @@ define SetupJavaCompilationBody # 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 --git a/modules.xml b/modules.xml index d7db4ed42d8..8cb87dd0766 100644 --- a/modules.xml +++ b/modules.xml @@ -238,6 +238,12 @@ jdk.management.resource jdk.scripting.nashorn + + jdk.internal.perf + java.desktop + java.management + jdk.jvmstat + jdk.internal.org.objectweb.asm java.instrument diff --git a/nashorn/.hgtags b/nashorn/.hgtags index a50648283a7..b4dc358f38d 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -334,3 +334,4 @@ d52c09d5d98a81ee6102a25f662ec4b9ae614163 jdk-9+96 68a36216f70c0de4c7e36f8978995934fc72ec03 jdk-9+98 74ddd1339c57cf2c2a13e34e1760006c2e54d1fc jdk-9+99 da397aea8adad7e6f743b60bfe0c415fc8508df5 jdk-9+100 +1916a2c680d8c33b59943dbb6dc2dd2000ec821a jdk-9+101 diff --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java index 72c35a99b7e..035b492d751 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java @@ -349,55 +349,121 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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; + } - while(!operations.isEmpty()) { - final GuardedInvocationComponent gic = - getGuardedInvocationComponent(callSiteDescriptor, - linkerServices, operations, name); - if(gic != null) { - return gic.getGuardedInvocation(); + 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); + } + + 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { // 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { // 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { "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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { // 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { // 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 { - // 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); + private GuardedInvocationComponent getMethodGetter(final ComponentLinkRequest req) throws Exception { + if (req.name == null) { + return getUnnamedMethodGetter(req); } - - return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type); + return getNamedMethodGetter(req); } - private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor, - final LinkerServices linkerServices, final List ops, final MethodType type) throws Exception { + 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. + return req.getDescriptor().getMethodType().changeReturnType(Object.class); + } + + 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker { 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java index dc9b4fe4e8e..9b580f12df2 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java @@ -88,6 +88,7 @@ import java.lang.invoke.MethodHandles; 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL } @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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL // 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL } 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL } 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL // 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 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java index b68d1aa58f1..4ea49f2e560 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java @@ -146,7 +146,11 @@ import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; * 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 @@ public class BeansLinker implements GuardingDynamicLinker { } }; + 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 @@ public class BeansLinker implements GuardingDynamicLinker { * @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 @@ public class BeansLinker implements GuardingDynamicLinker { * @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 @@ public class BeansLinker implements GuardingDynamicLinker { * @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 @@ public class BeansLinker implements GuardingDynamicLinker { * @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 @@ public class BeansLinker implements GuardingDynamicLinker { // 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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/LinkerServicesWithMissingMemberHandlerFactory.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/LinkerServicesWithMissingMemberHandlerFactory.java new file mode 100644 index 00000000000..916eced7c2f --- /dev/null +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/LinkerServicesWithMissingMemberHandlerFactory.java @@ -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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java new file mode 100644 index 00000000000..1fe50b916d9 --- /dev/null +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java @@ -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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java index 9ca1b52f33f..c81e8d1f8d8 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java @@ -91,6 +91,7 @@ import java.util.Arrays; 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; @@ -161,6 +162,27 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker { return null; } + @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 --git a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java index bc5b260e4ff..87993a3c1d4 100644 --- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java +++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java @@ -202,6 +202,9 @@ public class GuardedInvocation { 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 @@ public class GuardedInvocation { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java index 8db99dd6fd5..136c2f97880 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java @@ -1133,6 +1133,8 @@ public final class Global extends Scope { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java index 5151e8bf419..4441dd8bed8 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java @@ -284,8 +284,8 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin // 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 @@ -908,21 +908,6 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin return getContinuousNonEmptyArrayDataCCE(self, IntElements.class).fastPopInt(); } - /** - * 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 long popLong(final Object self) { - //must be non empty Int or LongArrayData - return getContinuousNonEmptyArrayDataCCE(self, IntOrLongElements.class).fastPopLong(); - } - /** * Specialization of pop for ContinuousArrayData * @@ -997,7 +982,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * @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 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * @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 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * @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 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * @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 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * @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 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * @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 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin * @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java index bda848d8c00..0bafc47a46c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeBoolean.java @@ -168,9 +168,9 @@ public final class NativeBoolean extends ScriptObject { } /** - * 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java index 3d3f24899de..78dd464be9a 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java @@ -256,8 +256,9 @@ public final class NativeDate extends ScriptObject { * @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java index 84513b5b511..c52e1b35fe8 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeNumber.java @@ -48,6 +48,7 @@ import jdk.nashorn.internal.runtime.PropertyMap; 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 @@ public final class NativeNumber extends ScriptObject { * @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java index 1f1488a7e33..bdd8c2a9cd1 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java @@ -776,7 +776,7 @@ public final class NativeObject { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java index 0df0eca4a3c..1ec733cf32e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java @@ -74,7 +74,7 @@ public final class NativeRegExpExecResult extends ScriptObject { @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java index 52e326a3fae..0b7869b8844 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java @@ -146,7 +146,7 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti 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 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti * @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java index 41f40680781..d2c316241b6 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeSymbol.java @@ -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.ScriptObject; 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 @@ public final class NativeSymbol extends ScriptObject { 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 @@ public final class NativeSymbol extends ScriptObject { } } + /** + * 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 @@ public final class NativeSymbol extends ScriptObject { 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java index 2ecd40cc577..b791acd92d1 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java @@ -178,6 +178,12 @@ public enum JSType { /** 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 @@ public enum JSType { return JSType.STRING; } - if (obj instanceof Number) { + if (isNumber(obj)) { return JSType.NUMBER; } @@ -322,7 +328,7 @@ public enum JSType { return JSType.STRING; } - if (obj instanceof Number) { + if (isNumber(obj)) { return JSType.NUMBER; } @@ -434,7 +440,7 @@ public enum JSType { return obj == null || obj == ScriptRuntime.UNDEFINED || isString(obj) || - obj instanceof Number || + isNumber(obj) || obj instanceof Boolean || obj instanceof Symbol; } @@ -609,6 +615,24 @@ public enum JSType { return obj instanceof String || obj instanceof ConsString; } + /** + * 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 * @@ -761,7 +785,7 @@ public enum JSType { 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 @@ public enum JSType { return obj.toString(); } - if (obj instanceof Number) { + if (isNumber(obj)) { return toString(((Number)obj).doubleValue()); } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java index bb29198bc5d..da172b07939 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java @@ -94,6 +94,9 @@ public final class Undefined extends DefaultPropertyAccess { */ 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java index 81146a39383..f891afad46e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java @@ -287,7 +287,7 @@ public abstract class ContinuousArrayData extends ArrayData { * @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 @@ public abstract class ContinuousArrayData extends ArrayData { * @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 @@ public abstract class ContinuousArrayData extends ArrayData { * @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 @@ public abstract class ContinuousArrayData extends ArrayData { * @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 } @@ -326,14 +326,6 @@ public abstract class ContinuousArrayData extends ArrayData { throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink } - /** - * 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 diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java index b7837bbaeaa..ef899fc691c 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java @@ -340,7 +340,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { } @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)); @@ -361,11 +361,6 @@ final class IntArrayData extends ContinuousArrayData implements IntElements { return elem; } - @Override - public long fastPopLong() { - return fastPopInt(); - } - @Override public double fastPopDouble() { return fastPopInt(); diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java index 5f70751e41f..73fcb083d72 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java @@ -303,17 +303,17 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen } @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java index 27b7d91772f..cb99de829f4 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java @@ -236,22 +236,22 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements { } @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java index eecb008922f..3e41a7dcd6a 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -40,10 +40,11 @@ import jdk.dynalink.DynamicLinkerFactory; 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 @@ public final class Bootstrap { 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 final class Bootstrap { 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.setAutoConversionStrategy(new MethodTypeConversionStrategy() { - @Override - public MethodHandle asType(final MethodHandle target, final MethodType newType) { - return unboxReturnType(target, newType); - } + factory.setPrelinkTransformer((inv, request, linkerServices) -> { + final CallSiteDescriptor desc = request.getCallSiteDescriptor(); + return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType()); }); + factory.setAutoConversionStrategy(Bootstrap::unboxReturnType); factory.setInternalObjectsFilter(NashornBeansLinker.createHiddenObjectFilter()); factory.setUnstableRelinkThreshold(unstableRelinkThreshold); @@ -114,6 +116,15 @@ public final class Bootstrap { return factory.createLinker(); } + /** + * 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 @@ -475,4 +486,14 @@ public final class Bootstrap { } 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java index 669badfaba3..6629b1ada5d 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java @@ -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 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { 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 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { // 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 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker { */ @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java index 97c6b404943..19d5fa9dd74 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java @@ -85,7 +85,11 @@ public class NashornBeansLinker implements GuardingDynamicLinker { } }; - 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java index 79353d02cea..8c4735f234e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java @@ -27,26 +27,27 @@ package jdk.nashorn.internal.runtime.linker; 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 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo // 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 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo 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 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo 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 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo 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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornGuards.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornGuards.java index a3cbe3480c9..32368c07a06 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornGuards.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornGuards.java @@ -34,6 +34,7 @@ import jdk.dynalink.CallSiteDescriptor; 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 @@ import jdk.nashorn.internal.runtime.options.Options; 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 @@ public final class NashornGuards { } /** - * 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(); } /** @@ -223,11 +230,6 @@ public final class NashornGuards { return self == ref.get(); } - @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java index c73d24fa4cb..16778813a95 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java @@ -41,6 +41,7 @@ import jdk.nashorn.internal.objects.Global; 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 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu } 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 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu @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 --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java index a6c1d4a012d..8201aa631cf 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java @@ -53,7 +53,11 @@ import jdk.nashorn.internal.runtime.ECMAErrors; * */ 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 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker { 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 --git a/nashorn/test/script/basic/JDK-8030200.js b/nashorn/test/script/basic/JDK-8030200.js index a62fa498723..5803d54c579 100644 --- a/nashorn/test/script/basic/JDK-8030200.js +++ b/nashorn/test/script/basic/JDK-8030200.js @@ -33,4 +33,4 @@ print(n); var s = n.toString(5); var m = parseInt(s, 5); print(m === n); -print(n); +print(m); diff --git a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED index 660ec15af11..cec6dd89ffb 100644 --- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/JDK-8066669.js b/nashorn/test/script/basic/JDK-8066669.js index ea5a2860cac..65371e57faf 100644 --- a/nashorn/test/script/basic/JDK-8066669.js +++ b/nashorn/test/script/basic/JDK-8066669.js @@ -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["foo"], map["foo"]); 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 --git a/nashorn/test/script/basic/JDK-8066669.js.EXPECTED b/nashorn/test/script/basic/JDK-8066669.js.EXPECTED index 4af5381706a..86b817d1a5c 100644 --- a/nashorn/test/script/basic/JDK-8066669.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8066669.js.EXPECTED @@ -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 --git a/nashorn/test/script/basic/JDK-8079145.js.EXPECTED b/nashorn/test/script/basic/JDK-8079145.js.EXPECTED index 6b84c5e66b5..aef418432e2 100644 --- a/nashorn/test/script/basic/JDK-8079145.js.EXPECTED +++ b/nashorn/test/script/basic/JDK-8079145.js.EXPECTED @@ -5,8 +5,8 @@ int array: check widen for false [class java.lang.Boolean] 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 false [class java.lang.Boolean] 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 false [class java.lang.Boolean] 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 false [class java.lang.Boolean] 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 --git a/nashorn/test/script/basic/JDK-8143896.js b/nashorn/test/script/basic/JDK-8143896.js new file mode 100644 index 00000000000..84bcd669018 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8143896.js @@ -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 --git a/nashorn/test/script/basic/es6/symbols.js b/nashorn/test/script/basic/es6/symbols.js index efaa79ed3df..f5f70aae458 100644 --- a/nashorn/test/script/basic/es6/symbols.js +++ b/nashorn/test/script/basic/es6/symbols.js @@ -40,11 +40,11 @@ Assert.assertTrue(Symbol([1, 2, 3]).toString() === 'Symbol(1,2,3)'); 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['bar'] === 'bar'); 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 @@ try { // 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(Symbol.keyFor(cached) === 'foo'); 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(typeof o === 'object'); 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 --git a/nashorn/test/script/basic/list.js b/nashorn/test/script/basic/list.js index acbffca72be..c1f7de42f95 100644 --- a/nashorn/test/script/basic/list.js +++ b/nashorn/test/script/basic/list.js @@ -54,15 +54,14 @@ print("l['blah']=" + l['blah']) // non-number indices don't retrieve anything... 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 --git a/nashorn/test/script/basic/list.js.EXPECTED b/nashorn/test/script/basic/list.js.EXPECTED index 3e4109828aa..57846fccd46 100644 --- a/nashorn/test/script/basic/list.js.EXPECTED +++ b/nashorn/test/script/basic/list.js.EXPECTED @@ -9,9 +9,14 @@ bar --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 --git a/nashorn/test/script/basic/map.js b/nashorn/test/script/basic/map.js index 79bf3d3f019..c17e8453a22 100644 --- a/nashorn/test/script/basic/map.js +++ b/nashorn/test/script/basic/map.js @@ -44,8 +44,8 @@ print("m.empty = " + m.empty) // prints "false" 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 --git a/nashorn/test/script/basic/map.js.EXPECTED b/nashorn/test/script/basic/map.js.EXPECTED index 471e86e9f1b..b83609ab158 100644 --- a/nashorn/test/script/basic/map.js.EXPECTED +++ b/nashorn/test/script/basic/map.js.EXPECTED @@ -7,8 +7,8 @@ m = {empty=foo} 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 --git a/nashorn/test/script/nosecurity/context-dependent-logging.js b/nashorn/test/script/nosecurity/context-dependent-logging.js new file mode 100644 index 00000000000..65391fa3457 --- /dev/null +++ b/nashorn/test/script/nosecurity/context-dependent-logging.js @@ -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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { 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 @@ public class BeanLinkerTest { 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 @@ public class BeanLinkerTest { 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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { try { obj = cs.getTarget().invoke(Date.class); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -274,7 +354,7 @@ public class BeanLinkerTest { try { obj = cs.getTarget().invoke(Object[].class); - } catch (Throwable th) { + } catch (final Throwable th) { throw new RuntimeException(th); } @@ -285,14 +365,14 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { 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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { 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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 @@ public class BeanLinkerTest { @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 --git a/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java b/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java index 33bffbbf645..8ef147fab44 100644 --- a/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java +++ b/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java @@ -33,6 +33,7 @@ import static jdk.dynalink.StandardOperation.SET_PROPERTY; 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.CallSiteDescriptor; 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 @@ public class BeansLinkerTest { 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 @@ public class BeansLinkerTest { 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 --git a/nashorn/test/src/jdk/dynalink/beans/test/CallerSensitiveTest.java b/nashorn/test/src/jdk/dynalink/beans/test/CallerSensitiveTest.java index 0e0d8c2d127..68656c7d039 100644 --- a/nashorn/test/src/jdk/dynalink/beans/test/CallerSensitiveTest.java +++ b/nashorn/test/src/jdk/dynalink/beans/test/CallerSensitiveTest.java @@ -33,6 +33,6 @@ import org.testng.annotations.Test; public class CallerSensitiveTest { @Test public void testCallerSensitive() { - BeansLinker.getLinkerForClass(ClassLoaderAware.class); + new BeansLinker().getLinkerForClass(ClassLoaderAware.class); } } diff --git a/test/make/TestJavaCompilation.gmk b/test/make/TestJavaCompilation.gmk index 40f64018e00..f38d02c4327 100644 --- a/test/make/TestJavaCompilation.gmk +++ b/test/make/TestJavaCompilation.gmk @@ -239,6 +239,7 @@ TEST_TARGETS += $(OUTPUT_DIR)/_jar3_updated $(eval $(call SetupJavaCompiler,BOOT_JAVAC, \ JAVAC := $(JAVAC), \ + DISABLE_SJAVAC := true, \ )) JAVA_SRC_ROOT1 := $(OUTPUT_DIR)/javaroot1