diff --git a/.hgtags b/.hgtags index 60b05ec4f24..001205086b5 100644 --- a/.hgtags +++ b/.hgtags @@ -398,3 +398,4 @@ ab2c8b03c3284fcbdd157551a66f807e3a182d9b jdk-9+152 d7034ff7f8e257e81c9f95c7785dd4eaaa3c2afc jdk-9+153 8c70d170e62c0c58b5bc3ba666bd140399b98c9c jdk-10+0 45b751afd11e6c05991cf4913c5a0ac3304fcc4e jdk-9+154 +f4aff695ffe05cfdb69d8af25a4ddc6a029754ea jdk-9+155 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index b24ec390424..3d81f131af0 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -397,3 +397,4 @@ b119012d1c2ab2570fe8718633840d0c1f1f441d jdk-9+149 ef056360ddf3977d7d2ddbeb456a4d612d19ea05 jdk-9+152 816a6d03a7c44edfbd8780110529f1bdc3964fb9 jdk-9+153 8d26916eaa21b689835ffc1c0dbf12470aa9be61 jdk-9+154 +688a3863c00ebc089ab17ee1fc46272cbbd96815 jdk-9+155 diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index 17c03533dd7..35e835c3994 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -746,7 +746,8 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], fi # set SDKROOT too, Xcode tools will pick it up - AC_SUBST(SDKROOT,$SYSROOT) + SDKROOT="$SYSROOT" + AC_SUBST(SDKROOT) fi # Prepend the extra path to the global path @@ -831,9 +832,10 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], CONFIGURESUPPORT_OUTPUTDIR="$OUTPUT_ROOT/configure-support" $MKDIR -p "$CONFIGURESUPPORT_OUTPUTDIR" - AC_SUBST(SPEC, $OUTPUT_ROOT/spec.gmk) - AC_SUBST(CONF_NAME, $CONF_NAME) - AC_SUBST(OUTPUT_ROOT, $OUTPUT_ROOT) + SPEC="$OUTPUT_ROOT/spec.gmk" + AC_SUBST(SPEC) + AC_SUBST(CONF_NAME) + AC_SUBST(OUTPUT_ROOT) AC_SUBST(CONFIGURESUPPORT_OUTPUTDIR) # The spec.gmk file contains all variables for the make system. diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index 7eafd2857d3..b7ae10542ed 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -325,7 +325,6 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK], fi AC_MSG_CHECKING([if Boot JDK is 32 or 64 bits]) AC_MSG_RESULT([$BOOT_JDK_BITS]) - AC_SUBST(BOOT_JDK_BITS) ]) AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], diff --git a/common/autoconf/build-performance.m4 b/common/autoconf/build-performance.m4 index fd77fe8c2b0..13578cfa867 100644 --- a/common/autoconf/build-performance.m4 +++ b/common/autoconf/build-performance.m4 @@ -224,7 +224,7 @@ AC_DEFUN([BPERF_SETUP_CCACHE_USAGE], AC_MSG_ERROR([On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION]) fi fi - if test "x$USE_PRECOMPILED_HEADER" = "x1"; then + if test "x$USE_PRECOMPILED_HEADER" = "xtrue"; then HAS_BAD_CCACHE=[`$ECHO $CCACHE_VERSION | \ $GREP -e '^1.*' -e '^2.*' -e '^3\.0.*' -e '^3\.1\.[0123]$'`] if test "x$HAS_BAD_CCACHE" != "x"; then @@ -362,20 +362,20 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS], [disable using precompiled headers when compiling C++ @<:@enabled@:>@])], [ENABLE_PRECOMPH=${enable_precompiled_headers}], [ENABLE_PRECOMPH=yes]) - USE_PRECOMPILED_HEADER=1 + USE_PRECOMPILED_HEADER=true AC_MSG_CHECKING([If precompiled header is enabled]) if test "x$ENABLE_PRECOMPH" = xno; then AC_MSG_RESULT([no, forced]) - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false elif test "x$ICECC" != "x"; then AC_MSG_RESULT([no, does not work effectively with icecc]) - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then AC_MSG_RESULT([no, does not work with Solaris Studio]) - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false elif test "x$TOOLCHAIN_TYPE" = xxlc; then AC_MSG_RESULT([no, does not work with xlc]) - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false else AC_MSG_RESULT([yes]) fi @@ -387,7 +387,7 @@ AC_DEFUN_ONCE([BPERF_SETUP_PRECOMPILED_HEADERS], echo "int alfa();" > conftest.h $CXX -x c++-header conftest.h -o conftest.hpp.gch 2>&AS_MESSAGE_LOG_FD >&AS_MESSAGE_LOG_FD if test ! -f conftest.hpp.gch; then - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index e5ae8eed060..ca7f625664c 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -808,7 +808,7 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], IF_FALSE: [$2CXXSTD_CXXFLAG=""]) $2CXXFLAGS_JDK="${$2CXXFLAGS_JDK} ${$2CXXSTD_CXXFLAG}" $2JVM_CFLAGS="${$2JVM_CFLAGS} ${$2CXXSTD_CXXFLAG}" - AC_SUBST([$2CXXSTD_CXXFLAG]) + AC_SUBST($2CXXSTD_CXXFLAG) fi if test "x$OPENJDK_TARGET_OS" = xsolaris; then $2CFLAGS_JDK="${$2CFLAGS_JDK} -D__solaris__" @@ -1440,18 +1440,6 @@ BASIC_DEFUN_NAMED([FLAGS_LINKER_CHECK_ARGUMENTS], AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], [ - # Some Zero and Shark settings. - # ZERO_ARCHFLAG tells the compiler which mode to build for - case "${OPENJDK_TARGET_CPU}" in - s390) - ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}31" - ;; - *) - ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" - esac - 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(ARGUMENT: [${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}], @@ -1476,15 +1464,7 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], AC_MSG_ERROR([--enable-warnings-as-errors accepts no argument]) fi - if test "x$WARNINGS_AS_ERRORS" = "xfalse"; then - # Set legacy hotspot variable - HOTSPOT_SET_WARNINGS_AS_ERRORS="WARNINGS_ARE_ERRORS=" - else - HOTSPOT_SET_WARNINGS_AS_ERRORS="" - fi - AC_SUBST(WARNINGS_AS_ERRORS) - AC_SUBST(HOTSPOT_SET_WARNINGS_AS_ERRORS) case "${TOOLCHAIN_TYPE}" in microsoft) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 3c0f4644798..917181abf10 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -704,7 +704,6 @@ FIXPATH_DETACH_FLAG FIXPATH BUILD_GTEST ENABLE_AOT -INCLUDE_DTRACE GCOV_ENABLED ZIP_EXTERNAL_DEBUG_SYMBOLS COPY_DEBUG_SYMBOLS @@ -712,10 +711,8 @@ COMPILE_WITH_DEBUG_SYMBOLS CFLAGS_WARNINGS_ARE_ERRORS BUILD_CC_DISABLE_WARNING_PREFIX DISABLE_WARNING_PREFIX -HOTSPOT_SET_WARNINGS_AS_ERRORS WARNINGS_AS_ERRORS COMPILER_SUPPORTS_TARGET_BITS_FLAG -ZERO_ARCHFLAG LDFLAGS_TESTEXE LDFLAGS_TESTLIB CXXFLAGS_TESTEXE @@ -884,7 +881,6 @@ BUILD_JDK CREATE_BUILDJDK JLINK JMOD -BOOT_JDK_BITS JAVAC_FLAGS BOOT_JDK_MODULAR BOOT_JDK_SOURCETARGET @@ -974,15 +970,12 @@ CANONICAL_TOPDIR ORIGINAL_TOPDIR TOPDIR PATH_SEP -ZERO_ARCHDEF HOTSPOT_BUILD_CPU_DEFINE HOTSPOT_BUILD_CPU_ARCH HOTSPOT_BUILD_CPU HOTSPOT_BUILD_OS_TYPE HOTSPOT_BUILD_OS OPENJDK_BUILD_BUNDLE_PLATFORM -OPENJDK_BUILD_CPU_BUNDLE -OPENJDK_BUILD_OS_BUNDLE OPENJDK_BUILD_OS_EXPORT_DIR OPENJDK_BUILD_CPU_OSARCH OPENJDK_BUILD_CPU_ISADIR @@ -994,10 +987,7 @@ HOTSPOT_TARGET_CPU HOTSPOT_TARGET_OS_TYPE HOTSPOT_TARGET_OS DEFINE_CROSS_COMPILE_ARCH -LP64 OPENJDK_TARGET_BUNDLE_PLATFORM -OPENJDK_TARGET_CPU_BUNDLE -OPENJDK_TARGET_OS_BUNDLE OPENJDK_TARGET_OS_EXPORT_DIR OPENJDK_TARGET_CPU_OSARCH OPENJDK_TARGET_CPU_ISADIR @@ -3818,7 +3808,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # ... then the rest # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -3998,7 +3988,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -4273,7 +4263,7 @@ pkgadd_help() { # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -4561,7 +4551,7 @@ VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom" # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -4841,7 +4831,7 @@ VALID_JVM_VARIANTS="server client minimal core zero zeroshark custom" # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -5180,7 +5170,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=1485508515 +DATE_WHEN_GENERATED=1486175373 ############################################################################### # @@ -15936,18 +15926,14 @@ $as_echo "$COMPILE_TYPE" >&6; } OPENJDK_TARGET_BUNDLE_PLATFORM="${OPENJDK_TARGET_OS_BUNDLE}-${OPENJDK_TARGET_CPU_BUNDLE}" - - if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then - A_LP64="LP64:=" # -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in - # unpack200.exe + # unpack200.exe. This variable is used in + # FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER. if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xmacosx; then OPENJDK_TARGET_ADD_LP64="-D_LP64=1" fi fi - LP64=$A_LP64 - if test "x$COMPILE_TYPE" = "xcross"; then # FIXME: ... or should this include reduced builds..? @@ -16092,18 +16078,14 @@ $as_echo "$COMPILE_TYPE" >&6; } OPENJDK_BUILD_BUNDLE_PLATFORM="${OPENJDK_BUILD_OS_BUNDLE}-${OPENJDK_BUILD_CPU_BUNDLE}" - - if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then - A_LP64="LP64:=" # -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in - # unpack200.exe + # unpack200.exe. This variable is used in + # FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER. if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then OPENJDK_BUILD_ADD_LP64="-D_LP64=1" fi fi - LP64=$A_LP64 - if test "x$COMPILE_TYPE" = "xcross"; then # FIXME: ... or should this include reduced builds..? @@ -16173,12 +16155,6 @@ $as_echo "$COMPILE_TYPE" >&6; } - # ZERO_ARCHDEF is used to enable architecture-specific code. - # This is used in legacy hotspot build. - ZERO_ARCHDEF="$HOTSPOT_TARGET_CPU_DEFINE" - - - # Continue setting up basic stuff. Most remaining code require fundamental tools. @@ -17280,7 +17256,7 @@ $as_echo "$as_me: WARNING: Both SYSROOT and --with-sdk-name are set, only SYSROO fi # set SDKROOT too, Xcode tools will pick it up - SDKROOT=$SYSROOT + SDKROOT="$SYSROOT" fi @@ -17528,11 +17504,9 @@ $as_echo "$as_me: The path of OUTPUT_ROOT, which resolves as \"$path\", is inval CONFIGURESUPPORT_OUTPUTDIR="$OUTPUT_ROOT/configure-support" $MKDIR -p "$CONFIGURESUPPORT_OUTPUTDIR" - SPEC=$OUTPUT_ROOT/spec.gmk + SPEC="$OUTPUT_ROOT/spec.gmk" - CONF_NAME=$CONF_NAME - OUTPUT_ROOT=$OUTPUT_ROOT @@ -30730,7 +30704,6 @@ $as_echo "$BOOT_JDK_BITS" >&6; } - # Check whether --with-build-jdk was given. if test "${with_build_jdk+set}" = set; then : withval=$with_build_jdk; @@ -51480,282 +51453,6 @@ OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${OPENJDK_BUILD_JA - # Some Zero and Shark settings. - # ZERO_ARCHFLAG tells the compiler which mode to build for - case "${OPENJDK_TARGET_CPU}" in - s390) - ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}31" - ;; - *) - ZERO_ARCHFLAG="${COMPILER_TARGET_BITS_FLAG}${OPENJDK_TARGET_CPU_BITS}" - esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Execute function body - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Execute function body - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the C compiler supports \"$ZERO_ARCHFLAG\"" >&5 -$as_echo_n "checking if the C compiler supports \"$ZERO_ARCHFLAG\"... " >&6; } - supports=yes - - saved_cflags="$CFLAGS" - CFLAGS="$CFLAGS $ZERO_ARCHFLAG" - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - supports=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - CFLAGS="$saved_cflags" - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 -$as_echo "$supports" >&6; } - if test "x$supports" = "xyes" ; then - : - C_COMP_SUPPORTS="yes" - else - : - C_COMP_SUPPORTS="no" - fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Execute function body - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the C++ compiler supports \"$ZERO_ARCHFLAG\"" >&5 -$as_echo_n "checking if the C++ compiler supports \"$ZERO_ARCHFLAG\"... " >&6; } - supports=yes - - saved_cxxflags="$CXXFLAGS" - CXXFLAGS="$CXXFLAG $ZERO_ARCHFLAG" - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -_ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : - -else - supports=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - CXXFLAGS="$saved_cxxflags" - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 -$as_echo "$supports" >&6; } - if test "x$supports" = "xyes" ; then - : - CXX_COMP_SUPPORTS="yes" - else - : - CXX_COMP_SUPPORTS="no" - fi - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if both compilers support \"$ZERO_ARCHFLAG\"" >&5 -$as_echo_n "checking if both compilers support \"$ZERO_ARCHFLAG\"... " >&6; } - supports=no - if test "x$C_COMP_SUPPORTS" = "xyes" -a "x$CXX_COMP_SUPPORTS" = "xyes"; then supports=yes; fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5 -$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 @@ -52054,14 +51751,6 @@ $as_echo "yes (default)" >&6; } as_fn_error $? "--enable-warnings-as-errors accepts no argument" "$LINENO" 5 fi - if test "x$WARNINGS_AS_ERRORS" = "xfalse"; then - # Set legacy hotspot variable - HOTSPOT_SET_WARNINGS_AS_ERRORS="WARNINGS_ARE_ERRORS=" - else - HOTSPOT_SET_WARNINGS_AS_ERRORS="" - fi - - case "${TOOLCHAIN_TYPE}" in @@ -52916,7 +52605,6 @@ $as_echo "yes, dependencies present" >&6; } fi - # Check whether --enable-aot was given. if test "${enable_aot+set}" = set; then : enableval=$enable_aot; @@ -63694,12 +63382,14 @@ $as_echo_n "checking for which libpng to use... " >&6; } DEFAULT_LIBPNG=bundled # if user didn't specify, use DEFAULT_LIBPNG if test "x${with_libpng}" = "x"; then - with_libpng=${DEFAULT_LIBPNG} + with_libpng=${DEFAULT_LIBPNG} fi if test "x${with_libpng}" = "xbundled"; then - USE_EXTERNAL_LIBPNG=false - { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5 + USE_EXTERNAL_LIBPNG=false + PNG_CFLAGS="" + PNG_LIBS="" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5 $as_echo "bundled" >&6; } elif test "x${with_libpng}" = "xsystem"; then @@ -63759,33 +63449,36 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - LIBPNG_FOUND=no + LIBPNG_FOUND=no elif test $pkg_failed = untried; then - LIBPNG_FOUND=no + LIBPNG_FOUND=no else PNG_CFLAGS=$pkg_cv_PNG_CFLAGS PNG_LIBS=$pkg_cv_PNG_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - LIBPNG_FOUND=yes + LIBPNG_FOUND=yes fi - if test "x${LIBPNG_FOUND}" = "xyes"; then - USE_EXTERNAL_LIBPNG=true - { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5 + if test "x${LIBPNG_FOUND}" = "xyes"; then + # PKG_CHECK_MODULES will set PNG_CFLAGS and PNG_LIBS + USE_EXTERNAL_LIBPNG=true + { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5 $as_echo "system" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: system not found" >&5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: system not found" >&5 $as_echo "system not found" >&6; } - as_fn_error $? "--with-libpng=system specified, but no libpng found!" "$LINENO" 5 - fi + as_fn_error $? "--with-libpng=system specified, but no libpng found!" "$LINENO" 5 + fi else - as_fn_error $? "Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'" "$LINENO" 5 + as_fn_error $? "Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled'" "$LINENO" 5 fi + + # Check whether --with-zlib was given. if test "${with_zlib+set}" = set; then : withval=$with_zlib; @@ -63888,11 +63581,13 @@ $as_echo_n "checking for which lcms to use... " >&6; } DEFAULT_LCMS=bundled # If user didn't specify, use DEFAULT_LCMS if test "x${with_lcms}" = "x"; then - with_lcms=${DEFAULT_LCMS} + with_lcms=${DEFAULT_LCMS} fi if test "x${with_lcms}" = "xbundled"; then USE_EXTERNAL_LCMS=false + LCMS_CFLAGS="" + LCMS_LIBS="" { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5 $as_echo "bundled" >&6; } elif test "x${with_lcms}" = "xsystem"; then @@ -63966,6 +63661,7 @@ $as_echo "yes" >&6; } LCMS_FOUND=yes fi if test "x${LCMS_FOUND}" = "xyes"; then + # PKG_CHECK_MODULES will set LCMS_CFLAGS and LCMS_LIBS USE_EXTERNAL_LCMS=true else as_fn_error $? "--with-lcms=system specified, but no lcms found!" "$LINENO" 5 @@ -63984,6 +63680,8 @@ fi + + # Setup libm (the maths library) if test "x$OPENJDK_TARGET_OS" != "xwindows"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5 @@ -64768,11 +64466,11 @@ fi $as_echo_n "checking if elliptic curve crypto implementation is present... " >&6; } if test -d "${SRC_ROOT}/jdk/src/jdk.crypto.ec/share/native/libsunec/impl"; then - ENABLE_INTREE_EC=yes + ENABLE_INTREE_EC=true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else - ENABLE_INTREE_EC=no + ENABLE_INTREE_EC=false { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi @@ -66139,25 +65837,25 @@ else fi - USE_PRECOMPILED_HEADER=1 + USE_PRECOMPILED_HEADER=true { $as_echo "$as_me:${as_lineno-$LINENO}: checking If precompiled header is enabled" >&5 $as_echo_n "checking If precompiled header is enabled... " >&6; } if test "x$ENABLE_PRECOMPH" = xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, forced" >&5 $as_echo "no, forced" >&6; } - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false elif test "x$ICECC" != "x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work effectively with icecc" >&5 $as_echo "no, does not work effectively with icecc" >&6; } - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false elif test "x$TOOLCHAIN_TYPE" = xsolstudio; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work with Solaris Studio" >&5 $as_echo "no, does not work with Solaris Studio" >&6; } - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false elif test "x$TOOLCHAIN_TYPE" = xxlc; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, does not work with xlc" >&5 $as_echo "no, does not work with xlc" >&6; } - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -66171,7 +65869,7 @@ $as_echo_n "checking that precompiled headers work... " >&6; } echo "int alfa();" > conftest.h $CXX -x c++-header conftest.h -o conftest.hpp.gch 2>&5 >&5 if test ! -f conftest.hpp.gch; then - USE_PRECOMPILED_HEADER=0 + USE_PRECOMPILED_HEADER=false { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else @@ -66458,7 +66156,7 @@ $as_echo "$as_me: WARNING: --with-ccache-dir has no meaning when ccache is not e as_fn_error $? "On macosx, ccache 3.2 or later is required, found $CCACHE_VERSION" "$LINENO" 5 fi fi - if test "x$USE_PRECOMPILED_HEADER" = "x1"; then + if test "x$USE_PRECOMPILED_HEADER" = "xtrue"; then HAS_BAD_CCACHE=`$ECHO $CCACHE_VERSION | \ $GREP -e '^1.*' -e '^2.*' -e '^3\.0.*' -e '^3\.1\.[0123]$'` if test "x$HAS_BAD_CCACHE" != "x"; then diff --git a/common/autoconf/hotspot.m4 b/common/autoconf/hotspot.m4 index 79eb26c96c9..b295b015a9f 100644 --- a/common/autoconf/hotspot.m4 +++ b/common/autoconf/hotspot.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -189,7 +189,6 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_DTRACE], else AC_MSG_ERROR([Invalid value for --enable-dtrace: $enable_dtrace]) fi - AC_SUBST(INCLUDE_DTRACE) ]) ################################################################################ diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index 2c21000845b..bb2a49f4980 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -210,10 +210,10 @@ AC_DEFUN_ONCE([JDKOPT_DETECT_INTREE_EC], AC_MSG_CHECKING([if elliptic curve crypto implementation is present]) if test -d "${SRC_ROOT}/jdk/src/jdk.crypto.ec/share/native/libsunec/impl"; then - ENABLE_INTREE_EC=yes + ENABLE_INTREE_EC=true AC_MSG_RESULT([yes]) else - ENABLE_INTREE_EC=no + ENABLE_INTREE_EC=false AC_MSG_RESULT([no]) fi @@ -479,5 +479,5 @@ AC_DEFUN_ONCE([JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST], AC_MSG_ERROR([Invalid value for --enable-generate-classlist: $enable_generate_classlist]) fi - AC_SUBST([ENABLE_GENERATE_CLASSLIST]) + AC_SUBST(ENABLE_GENERATE_CLASSLIST) ]) diff --git a/common/autoconf/lib-bundled.m4 b/common/autoconf/lib-bundled.m4 index 218d3f87adf..92b9438014b 100644 --- a/common/autoconf/lib-bundled.m4 +++ b/common/autoconf/lib-bundled.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -119,28 +119,31 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBPNG], DEFAULT_LIBPNG=bundled # if user didn't specify, use DEFAULT_LIBPNG if test "x${with_libpng}" = "x"; then - with_libpng=${DEFAULT_LIBPNG} + with_libpng=${DEFAULT_LIBPNG} fi if test "x${with_libpng}" = "xbundled"; then - USE_EXTERNAL_LIBPNG=false - AC_MSG_RESULT([bundled]) + USE_EXTERNAL_LIBPNG=false + PNG_CFLAGS="" + PNG_LIBS="" + AC_MSG_RESULT([bundled]) elif test "x${with_libpng}" = "xsystem"; then - PKG_CHECK_MODULES(PNG, libpng, - [ LIBPNG_FOUND=yes ], - [ LIBPNG_FOUND=no ]) - if test "x${LIBPNG_FOUND}" = "xyes"; then - USE_EXTERNAL_LIBPNG=true - AC_MSG_RESULT([system]) - else - AC_MSG_RESULT([system not found]) - AC_MSG_ERROR([--with-libpng=system specified, but no libpng found!]) - fi + PKG_CHECK_MODULES(PNG, libpng, [LIBPNG_FOUND=yes], [LIBPNG_FOUND=no]) + if test "x${LIBPNG_FOUND}" = "xyes"; then + # PKG_CHECK_MODULES will set PNG_CFLAGS and PNG_LIBS + USE_EXTERNAL_LIBPNG=true + AC_MSG_RESULT([system]) + else + AC_MSG_RESULT([system not found]) + AC_MSG_ERROR([--with-libpng=system specified, but no libpng found!]) + fi else - AC_MSG_ERROR([Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled']) + AC_MSG_ERROR([Invalid value of --with-libpng: ${with_libpng}, use 'system' or 'bundled']) fi AC_SUBST(USE_EXTERNAL_LIBPNG) + AC_SUBST(PNG_CFLAGS) + AC_SUBST(PNG_LIBS) ]) ################################################################################ @@ -204,16 +207,19 @@ AC_DEFUN_ONCE([LIB_SETUP_LCMS], DEFAULT_LCMS=bundled # If user didn't specify, use DEFAULT_LCMS if test "x${with_lcms}" = "x"; then - with_lcms=${DEFAULT_LCMS} + with_lcms=${DEFAULT_LCMS} fi if test "x${with_lcms}" = "xbundled"; then USE_EXTERNAL_LCMS=false + LCMS_CFLAGS="" + LCMS_LIBS="" AC_MSG_RESULT([bundled]) elif test "x${with_lcms}" = "xsystem"; then AC_MSG_RESULT([system]) PKG_CHECK_MODULES([LCMS], [lcms2], [LCMS_FOUND=yes], [LCMS_FOUND=no]) if test "x${LCMS_FOUND}" = "xyes"; then + # PKG_CHECK_MODULES will set LCMS_CFLAGS and LCMS_LIBS USE_EXTERNAL_LCMS=true else AC_MSG_ERROR([--with-lcms=system specified, but no lcms found!]) @@ -223,4 +229,6 @@ AC_DEFUN_ONCE([LIB_SETUP_LCMS], fi AC_SUBST(USE_EXTERNAL_LCMS) + AC_SUBST(LCMS_CFLAGS) + AC_SUBST(LCMS_LIBS) ]) diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index 5217ca32e3e..61010279a0e 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -276,12 +276,6 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS], [ PLATFORM_SETUP_LEGACY_VARS_HELPER([TARGET]) PLATFORM_SETUP_LEGACY_VARS_HELPER([BUILD]) - - # ZERO_ARCHDEF is used to enable architecture-specific code. - # This is used in legacy hotspot build. - ZERO_ARCHDEF="$HOTSPOT_TARGET_CPU_DEFINE" - AC_SUBST(ZERO_ARCHDEF) - ]) # $1 - Either TARGET or BUILD to setup the variables for. @@ -360,19 +354,16 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], OPENJDK_$1_CPU_BUNDLE="$OPENJDK_$1_CPU" fi OPENJDK_$1_BUNDLE_PLATFORM="${OPENJDK_$1_OS_BUNDLE}-${OPENJDK_$1_CPU_BUNDLE}" - AC_SUBST(OPENJDK_$1_OS_BUNDLE) - AC_SUBST(OPENJDK_$1_CPU_BUNDLE) AC_SUBST(OPENJDK_$1_BUNDLE_PLATFORM) if test "x$OPENJDK_$1_CPU_BITS" = x64; then - A_LP64="LP64:=" # -D_LP64=1 is only set on linux and mac. Setting on windows causes diff in - # unpack200.exe + # unpack200.exe. This variable is used in + # FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER. if test "x$OPENJDK_$1_OS" = xlinux || test "x$OPENJDK_$1_OS" = xmacosx; then OPENJDK_$1_ADD_LP64="-D_LP64=1" fi fi - AC_SUBST(LP64,$A_LP64) if test "x$COMPILE_TYPE" = "xcross"; then # FIXME: ... or should this include reduced builds..? diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index 471f9096e01..bb6d2209c41 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -87,9 +87,8 @@ HOTSPOT_TARGET_CPU := @HOTSPOT_TARGET_CPU@ HOTSPOT_TARGET_CPU_ARCH := @HOTSPOT_TARGET_CPU_ARCH@ HOTSPOT_TARGET_CPU_DEFINE := @HOTSPOT_TARGET_CPU_DEFINE@ -OPENJDK_TARGET_CPU_BUNDLE:=@OPENJDK_TARGET_CPU_BUNDLE@ -OPENJDK_TARGET_OS_BUNDLE:=@OPENJDK_TARGET_OS_BUNDLE@ OPENJDK_TARGET_BUNDLE_PLATFORM:=@OPENJDK_TARGET_BUNDLE_PLATFORM@ +JDK_ARCH_ABI_PROP_NAME := @JDK_ARCH_ABI_PROP_NAME@ # We are building on this build system. # When not cross-compiling, it is the same as the target. @@ -683,8 +682,7 @@ TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@ # Build setup ENABLE_AOT:=@ENABLE_AOT@ -ENABLE_JFR=@ENABLE_JFR@ -ENABLE_INTREE_EC=@ENABLE_INTREE_EC@ +ENABLE_INTREE_EC:=@ENABLE_INTREE_EC@ USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@ diff --git a/common/bin/hgforest.sh b/common/bin/hgforest.sh index 3007d3e8860..5d4f8eb7156 100644 --- a/common/bin/hgforest.sh +++ b/common/bin/hgforest.sh @@ -309,8 +309,8 @@ if [ "${command}" = "serve" ] ; then echo "serving root repo ${serving}" > ${status_output} - echo "hg${global_opts} serve" > ${status_output} - (PYTHONUNBUFFERED=true hg${global_opts} serve -A ${status_output} -E ${status_output} --pid-file ${tmp}/serve.pid --web-conf ${tmp}/serve.web-conf; echo "$?" > ${tmp}/serve.pid.rc ) 2>&1 & + echo "hg${global_opts} serve ${@}" > ${status_output} + (PYTHONUNBUFFERED=true hg${global_opts} serve -A ${status_output} -E ${status_output} --pid-file ${tmp}/serve.pid --web-conf ${tmp}/serve.web-conf "${@}"; echo "$?" > ${tmp}/serve.pid.rc ) 2>&1 & ) 2>&1 | sed -e "s@^@serve: @" > ${status_output} ) & else diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt index a217a8f01f8..e5fe5af121d 100644 --- a/common/bin/unshuffle_list.txt +++ b/common/bin/unshuffle_list.txt @@ -60,7 +60,7 @@ jaxp/src/java.xml/share/classes/org/xml/sax : jaxp/src/org/xml/sax jaxws/src/java.activation/share/classes/com/sun/activation/registries : jaxws/src/share/jaf_classes/com/sun/activation/registries jaxws/src/java.activation/share/classes/javax/activation : jaxws/src/share/jaf_classes/javax/activation jaxws/src/java.activation/share/classes/META-INF : jaxws/src/share/jaf_classes/META-INF -jaxws/src/java.annotations.common/share/classes/javax/annotation : jaxws/src/share/jaxws_classes/javax/annotation +jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation : jaxws/src/share/jaxws_classes/javax/annotation jaxws/src/java.xml.bind/share/classes/com/sun/istack/internal : jaxws/src/share/jaxws_classes/com/sun/istack/internal jaxws/src/java.xml.bind/share/classes/com/sun/istack/internal/localization : jaxws/src/share/jaxws_classes/com/sun/istack/internal/localization jaxws/src/java.xml.bind/share/classes/com/sun/istack/internal/logging/Logger.java : jaxws/src/share/jaxws_classes/com/sun/istack/internal/logging/Logger.java @@ -1163,9 +1163,6 @@ jdk/src/java.management/share/classes/mgmt-overview.html : jdk/src/share/classes jdk/src/java.management/share/classes/sun/management/counter : jdk/src/share/classes/sun/management/counter jdk/src/java.management/share/classes/sun/management/counter/perf : jdk/src/share/classes/sun/management/counter/perf jdk/src/java.management/share/classes/sun/management : jdk/src/share/classes/sun/management -jdk/src/java.management/share/classes/sun/management/jdp : jdk/src/share/classes/sun/management/jdp -jdk/src/java.management/share/classes/sun/management/jmxremote : jdk/src/share/classes/sun/management/jmxremote -jdk/src/java.management/share/classes/sun/management/resources : jdk/src/share/classes/sun/management/resources jdk/src/java.management/share/conf : jdk/src/share/lib/management jdk/src/java.management/share/native/include/jmm.h : jdk/src/share/javavm/export/jmm.h jdk/src/java.management/share/native/libmanagement : jdk/src/share/native/sun/management @@ -1173,6 +1170,11 @@ jdk/src/java.management/unix/classes/sun/management : jdk/src/solaris/classes/su jdk/src/java.management/unix/native/libmanagement : jdk/src/solaris/native/sun/management jdk/src/java.management/windows/classes/sun/management : jdk/src/windows/classes/sun/management jdk/src/java.management/windows/native/libmanagement : jdk/src/windows/native/sun/management +jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/ProxyRef.java : jdk/src/share/classes/com/sun/jmx/remote/internal/ProxyRef.java +jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/RMIExporter.java : jdk/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java +jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/Unmarshal.java : jdk/src/share/classes/com/sun/jmx/remote/internal/Unmarshal.java +jdk/src/java.management.rmi/share/classes/com/sun/jmx/remote/protocol/rmi : jdk/src/share/classes/com/sun/jmx/remote/protocol/rmi +jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi : jdk/src/share/classes/javax/management/remote/rmi jdk/src/java.naming/share/classes/com/sun/jndi/ldap/ext : jdk/src/share/classes/com/sun/jndi/ldap/ext jdk/src/java.naming/share/classes/com/sun/jndi/ldap : jdk/src/share/classes/com/sun/jndi/ldap jdk/src/java.naming/share/classes/com/sun/jndi/ldap/pool : jdk/src/share/classes/com/sun/jndi/ldap/pool @@ -1330,9 +1332,9 @@ jdk/src/jdk.jdwp.agent/unix/native/libdt_socket : jdk/src/solaris/transport/sock jdk/src/jdk.jdwp.agent/unix/native/libjdwp : jdk/src/solaris/back jdk/src/jdk.jdwp.agent/windows/native/libdt_socket : jdk/src/windows/transport/socket jdk/src/jdk.jdwp.agent/windows/native/libjdwp : jdk/src/windows/back -jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/monitor : jdk/src/share/classes/sun/jvmstat/monitor -jdk/src/jdk.jvmstat/share/classes/sun/jvmstat/perfdata : jdk/src/share/classes/sun/jvmstat/perfdata -jdk/src/jdk.jvmstat/share/classes/sun/tools/jstatd : jdk/src/share/classes/sun/tools/jstatd +jdk/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/monitor : jdk/src/share/classes/sun/jvmstat/monitor +jdk/src/jdk.internal.jvmstat/share/classes/sun/jvmstat/perfdata : jdk/src/share/classes/sun/jvmstat/perfdata +jdk/src/jdk.internal.jvmstat/share/classes/sun/tools/jstatd : jdk/src/share/classes/sun/tools/jstatd jdk/src/jdk.localedata/share/classes/sun/text/resources/ar : jdk/src/share/classes/sun/text/resources/ar jdk/src/jdk.localedata/share/classes/sun/text/resources/be : jdk/src/share/classes/sun/text/resources/be jdk/src/jdk.localedata/share/classes/sun/text/resources/bg : jdk/src/share/classes/sun/text/resources/bg @@ -1421,6 +1423,9 @@ jdk/src/jdk.localedata/share/classes/sun/util/resources/uk : jdk/src/share/class jdk/src/jdk.localedata/share/classes/sun/util/resources/vi : jdk/src/share/classes/sun/util/resources/vi jdk/src/jdk.localedata/share/classes/sun/util/resources/zh : jdk/src/share/classes/sun/util/resources/zh jdk/src/jdk.management/share/classes/com/sun/management : jdk/src/share/classes/com/sun/management +jdk/src/jdk.management.agent/share/classes/jdk/internal/agent/resources : jdk/src/share/classes/sun/management/resources +jdk/src/jdk.management.agent/share/classes/sun/management/jmxremote : jdk/src/share/classes/sun/management/jmxremote +jdk/src/jdk.management.agent/share/classes/sun/management/jdp : jdk/src/share/classes/sun/management/jdp jdk/src/jdk.naming.dns/share/classes/com/sun/jndi/dns : jdk/src/share/classes/com/sun/jndi/dns jdk/src/jdk.naming.dns/share/classes/com/sun/jndi/url/dns : jdk/src/share/classes/com/sun/jndi/url/dns jdk/src/jdk.naming.dns/share/classes/META-INF/services : jdk/src/share/classes/sun/net/spi/nameservice/dns/META-INF/services diff --git a/corba/.hgtags b/corba/.hgtags index dd78cf97c29..7a24e3f5f23 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -397,3 +397,4 @@ f95cc86b6ac22ec1ade5d4f825dc7782adeea228 jdk-9+148 ff8cb43c07c069b1debdee44cb88ca22db1ec757 jdk-9+152 68a8e8658511093b322a46ed04b2a321e1da2a43 jdk-9+153 078ebe23b584466dc8346e620d7821d91751e5a9 jdk-9+154 +a545f54babfa31aa7eb611f36031609acd617cbc jdk-9+155 diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 8a3f632ef26..66afb5ed54b 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -557,3 +557,4 @@ a82cb5350cad96a0b4de496afebe3ded89f27efa jdk-9+146 31f1d26c60df7b2e516a4f84160d76ba017d4e09 jdk-9+152 217ba81b9a4ce8698200370175aa2db86a39f66c jdk-9+153 a9fdfd55835ef9dccb7f317b07249bd66653b874 jdk-9+154 +f3b3d77a1751897413aae43ac340a130b6fa2ae1 jdk-9+155 diff --git a/hotspot/make/ide/CreateVSProject.gmk b/hotspot/make/ide/CreateVSProject.gmk index d6f5324adb8..db0aca87e28 100644 --- a/hotspot/make/ide/CreateVSProject.gmk +++ b/hotspot/make/ide/CreateVSProject.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -121,7 +121,7 @@ ifeq ($(OPENJDK_TARGET_OS), windows) -buildBase $(call FixPath, $(IDE_OUTPUTDIR)/vs-output) \ -buildSpace $(call FixPath, $(IDE_OUTPUTDIR)) \ -makeBinary $(call FixPath, $(MAKE)) \ - -makeOutput $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-%f/libjvm) \ + -makeOutput $(call FixPath, $(JDK_OUTPUTDIR)/bin/server) \ -absoluteInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ -absoluteSrcInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \ $(EXTRACTED_DEFINES_client) \ diff --git a/hotspot/make/lib/CompileJvm.gmk b/hotspot/make/lib/CompileJvm.gmk index 870dde18d78..36d955807ad 100644 --- a/hotspot/make/lib/CompileJvm.gmk +++ b/hotspot/make/lib/CompileJvm.gmk @@ -63,7 +63,7 @@ JVM_CFLAGS_INCLUDES += \ # INCLUDE_SUFFIX_* is only meant for including the proper # platform files. Don't use it to guard code. Use the value of # HOTSPOT_TARGET_CPU_DEFINE etc. instead. -# Remaining TARGET_ARCH_* is needed to select the cpu specific +# Remaining TARGET_ARCH_* is needed to select the cpu specific # sources for 64-bit ARM ports (arm versus aarch64). JVM_CFLAGS_TARGET_DEFINES += \ -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \ @@ -132,7 +132,7 @@ CFLAGS_VM_VERSION := \ # # -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp. -ifeq ($(USE_PRECOMPILED_HEADER), 0) +ifeq ($(USE_PRECOMPILED_HEADER), false) JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER endif @@ -145,7 +145,7 @@ ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), linux-arm) JVM_EXCLUDE_PATTERNS += arm_64 else ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU), linux-aarch64) - # For 64-bit arm builds, we use the 64 bit hotspot/src/cpu/arm + # For 64-bit arm builds, we use the 64 bit hotspot/src/cpu/arm # hotspot sources if HOTSPOT_TARGET_CPU_ARCH is set to arm. # Exclude the aarch64 and 32 bit arm files for this build. ifeq ($(HOTSPOT_TARGET_CPU_ARCH), arm) diff --git a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java index d44fb04c588..50413e52792 100644 --- a/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java +++ b/hotspot/make/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,8 +114,8 @@ public class WinGammaPlatformVC10 extends WinGammaPlatform { tag(cfg, "CodeAnalysisRuleAssemblies"); } for (BuildConfig cfg : allConfigs) { - tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile import-hotspot LOG=info"); - tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot import-hotspot LOG=info"); + tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile hotspot LOG=info"); + tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot hotspot LOG=info"); tagData(cfg, "NMakeCleanCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot LOG=info"); tagData(cfg, "NMakeOutput", cfg.get("MakeOutput") + Util.sep + "jvm.dll"); tagData(cfg, "NMakePreprocessorDefinitions", Util.join(";", cfg.getDefines())); diff --git a/hotspot/make/symbols/symbols-unix b/hotspot/make/symbols/symbols-unix index 90326d263dc..11add06efac 100644 --- a/hotspot/make/symbols/symbols-unix +++ b/hotspot/make/symbols/symbols-unix @@ -192,4 +192,3 @@ JVM_AddModulePackage JVM_AddReadsModule JVM_DefineModule JVM_SetBootLoaderUnnamedModule -JVM_GetModuleByPackageName diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 2294bab8db8..37e63dc9aba 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -1042,8 +1042,10 @@ class HandlerImpl { bool is_card_mark_membar(const MemBarNode *barrier); bool is_CAS(int opcode); - MemBarNode *leading_to_trailing(MemBarNode *leading); - MemBarNode *card_mark_to_leading(const MemBarNode *barrier); + MemBarNode *leading_to_normal(MemBarNode *leading); + MemBarNode *normal_to_leading(const MemBarNode *barrier); + MemBarNode *card_mark_to_trailing(const MemBarNode *barrier); + MemBarNode *trailing_to_card_mark(const MemBarNode *trailing); MemBarNode *trailing_to_leading(const MemBarNode *trailing); // predicates controlling emit of ldr/ldar and associated dmb @@ -1420,28 +1422,23 @@ source %{ // leading MemBarRelease and a trailing MemBarVolatile as follows // // MemBarRelease - // { || } -- optional + // { || } -- optional // {MemBarCPUOrder} - // || \\ - // || StoreX[mo_release] - // | \ Bot / ??? - // | MergeMem - // | / + // || \\ + // || StoreX[mo_release] + // | \ / + // | MergeMem + // | / // MemBarVolatile // // where // || and \\ represent Ctl and Mem feeds via Proj nodes // | \ and / indicate further routing of the Ctl and Mem feeds // - // Note that the memory feed from the CPUOrder membar to the - // MergeMem node is an AliasIdxBot slice while the feed from the - // StoreX is for a slice determined by the type of value being - // written. - // - // the diagram above shows the graph we see for non-object stores. - // for a volatile Object store (StoreN/P) we may see other nodes - // below the leading membar because of the need for a GC pre- or - // post-write barrier. + // this is the graph we see for non-object stores. however, for a + // volatile Object store (StoreN/P) we may see other nodes below the + // leading membar because of the need for a GC pre- or post-write + // barrier. // // with most GC configurations we with see this simple variant which // includes a post-write barrier card mark. @@ -1449,7 +1446,7 @@ source %{ // MemBarRelease______________________________ // || \\ Ctl \ \\ // || StoreN/P[mo_release] CastP2X StoreB/CM - // | \ Bot / oop . . . / + // | \ / . . . / // | MergeMem // | / // || / @@ -1459,142 +1456,152 @@ source %{ // the object address to an int used to compute the card offset) and // Ctl+Mem to a StoreB node (which does the actual card mark). // - // n.b. a StoreCM node is only ever used when CMS (with or without - // CondCardMark) or G1 is configured. This abstract instruction - // differs from a normal card mark write (StoreB) because it implies - // a requirement to order visibility of the card mark (StoreCM) - // after that of the object put (StoreP/N) using a StoreStore memory - // barrier. Note that this is /not/ a requirement to order the - // instructions in the generated code (that is already guaranteed by - // the order of memory dependencies). Rather it is a requirement to - // ensure visibility order which only applies on architectures like - // AArch64 which do not implement TSO. This ordering is required for - // both non-volatile and volatile puts. - // - // That implies that we need to translate a StoreCM using the - // sequence + // n.b. a StoreCM node will only appear in this configuration when + // using CMS. StoreCM differs from a normal card mark write (StoreB) + // because it implies a requirement to order visibility of the card + // mark (StoreCM) relative to the object put (StoreP/N) using a + // StoreStore memory barrier (arguably this ought to be represented + // explicitly in the ideal graph but that is not how it works). This + // ordering is required for both non-volatile and volatile + // puts. Normally that means we need to translate a StoreCM using + // the sequence // // dmb ishst // stlrb // - // This dmb cannot be omitted even when the associated StoreX or - // CompareAndSwapX is implemented using stlr. However, as described - // below there are circumstances where a specific GC configuration - // requires a stronger barrier in which case it can be omitted. - // - // With the Serial or Parallel GC using +CondCardMark the card mark - // is performed conditionally on it currently being unmarked in - // which case the volatile put graph looks slightly different + // However, in the case of a volatile put if we can recognise this + // configuration and plant an stlr for the object write then we can + // omit the dmb and just plant an strb since visibility of the stlr + // is ordered before visibility of subsequent stores. StoreCM nodes + // also arise when using G1 or using CMS with conditional card + // marking. In these cases (as we shall see) we don't need to insert + // the dmb when translating StoreCM because there is already an + // intervening StoreLoad barrier between it and the StoreP/N. + // + // It is also possible to perform the card mark conditionally on it + // currently being unmarked in which case the volatile put graph + // will look slightly different // // MemBarRelease____________________________________________ // || \\ Ctl \ Ctl \ \\ Mem \ // || StoreN/P[mo_release] CastP2X If LoadB | - // | \ Bot / oop \ | + // | \ / \ | // | MergeMem . . . StoreB // | / / // || / // MemBarVolatile // - // It is worth noting at this stage that all the above + // It is worth noting at this stage that both the above // configurations can be uniquely identified by checking that the // memory flow includes the following subgraph: // // MemBarRelease // {MemBarCPUOrder} - // | \ . . . - // | StoreX[mo_release] . . . - // Bot | / oop - // MergeMem - // | + // | \ . . . + // | StoreX[mo_release] . . . + // | / + // MergeMem + // | // MemBarVolatile // - // This is referred to as a *normal* volatile store subgraph. It can - // easily be detected starting from any candidate MemBarRelease, - // StoreX[mo_release] or MemBarVolatile node. + // This is referred to as a *normal* subgraph. It can easily be + // detected starting from any candidate MemBarRelease, + // StoreX[mo_release] or MemBarVolatile. // - // A small variation on this normal case occurs for an unsafe CAS - // operation. The basic memory flow subgraph for a non-object CAS is - // as follows + // A simple variation on this normal case occurs for an unsafe CAS + // operation. The basic graph for a non-object CAS is // // MemBarRelease // || // MemBarCPUOrder - // | \\ . . . - // | CompareAndSwapX - // | | - // Bot | SCMemProj - // \ / Bot - // MergeMem - // / + // || \\ . . . + // || CompareAndSwapX + // || | + // || SCMemProj + // | \ / + // | MergeMem + // | / // MemBarCPUOrder // || // MemBarAcquire // // The same basic variations on this arrangement (mutatis mutandis) - // occur when a card mark is introduced. i.e. the CPUOrder MemBar - // feeds the extra CastP2X, LoadB etc nodes but the above memory - // flow subgraph is still present. - // - // This is referred to as a *normal* CAS subgraph. It can easily be - // detected starting from any candidate MemBarRelease, - // StoreX[mo_release] or MemBarAcquire node. + // occur when a card mark is introduced. i.e. we se the same basic + // shape but the StoreP/N is replaced with CompareAndSawpP/N and the + // tail of the graph is a pair comprising a MemBarCPUOrder + + // MemBarAcquire. // - // The code below uses two helper predicates, leading_to_trailing - // and trailing_to_leading to identify these normal graphs, one - // validating the layout starting from the top membar and searching - // down and the other validating the layout starting from the lower - // membar and searching up. + // So, in the case of a CAS the normal graph has the variant form // - // There are two special case GC configurations when the simple - // normal graphs above may not be generated: when using G1 (which - // always employs a conditional card mark); and when using CMS with - // conditional card marking (+CondCardMark) configured. These GCs - // are both concurrent rather than stop-the world GCs. So they - // introduce extra Ctl+Mem flow into the graph between the leading - // and trailing membar nodes, in particular enforcing stronger - // memory serialisation beween the object put and the corresponding - // conditional card mark. CMS employs a post-write GC barrier while - // G1 employs both a pre- and post-write GC barrier. + // MemBarRelease + // MemBarCPUOrder + // | \ . . . + // | CompareAndSwapX . . . + // | | + // | SCMemProj + // | / . . . + // MergeMem + // | + // MemBarCPUOrder + // MemBarAcquire // - // The post-write barrier subgraph for these configurations includes - // a MemBarVolatile node -- referred to as a card mark membar -- - // which is needed to order the card write (StoreCM) operation in - // the barrier, the preceding StoreX (or CompareAndSwapX) and Store - // operations performed by GC threads i.e. a card mark membar - // constitutes a StoreLoad barrier hence must be translated to a dmb - // ish (whether or not it sits inside a volatile store sequence). + // This graph can also easily be detected starting from any + // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire. // - // Of course, the use of the dmb ish for the card mark membar also - // implies theat the StoreCM which follows can omit the dmb ishst - // instruction. The necessary visibility ordering will already be - // guaranteed by the dmb ish. In sum, the dmb ishst instruction only - // needs to be generated for as part of the StoreCM sequence with GC - // configuration +CMS -CondCardMark. - // - // Of course all these extra barrier nodes may well be absent -- - // they are only inserted for object puts. Their potential presence - // significantly complicates the task of identifying whether a - // MemBarRelease, StoreX[mo_release], MemBarVolatile or - // MemBarAcquire forms part of a volatile put or CAS when using - // these GC configurations (see below) and also complicates the - // decision as to how to translate a MemBarVolatile and StoreCM. + // the code below uses two helper predicates, leading_to_normal and + // normal_to_leading to identify these normal graphs, one validating + // the layout starting from the top membar and searching down and + // the other validating the layout starting from the lower membar + // and searching up. // - // So, thjis means that a card mark MemBarVolatile occurring in the - // post-barrier graph it needs to be distinguished from a normal - // trailing MemBarVolatile. Resolving this is straightforward: a - // card mark MemBarVolatile always projects a Mem feed to a StoreCM - // node and that is a unique marker + // There are two special case GC configurations when a normal graph + // may not be generated: when using G1 (which always employs a + // conditional card mark); and when using CMS with conditional card + // marking configured. These GCs are both concurrent rather than + // stop-the world GCs. So they introduce extra Ctl+Mem flow into the + // graph between the leading and trailing membar nodes, in + // particular enforcing stronger memory serialisation beween the + // object put and the corresponding conditional card mark. CMS + // employs a post-write GC barrier while G1 employs both a pre- and + // post-write GC barrier. Of course the extra nodes may be absent -- + // they are only inserted for object puts. This significantly + // complicates the task of identifying whether a MemBarRelease, + // StoreX[mo_release] or MemBarVolatile forms part of a volatile put + // when using these GC configurations (see below). It adds similar + // complexity to the task of identifying whether a MemBarRelease, + // CompareAndSwapX or MemBarAcquire forms part of a CAS. + // + // In both cases the post-write subtree includes an auxiliary + // MemBarVolatile (StoreLoad barrier) separating the object put and + // the read of the corresponding card. This poses two additional + // problems. + // + // Firstly, a card mark MemBarVolatile needs to be distinguished + // from a normal trailing MemBarVolatile. Resolving this first + // problem is straightforward: a card mark MemBarVolatile always + // projects a Mem feed to a StoreCM node and that is a unique marker // // MemBarVolatile (card mark) // C | \ . . . // | StoreCM . . . // . . . // - // Returning to the task of translating the object put and the - // leading/trailing membar nodes: what do the node graphs look like - // for these 2 special cases? and how can we determine the status of - // a MemBarRelease, StoreX[mo_release] or MemBarVolatile in both - // normal and non-normal cases? + // The second problem is how the code generator is to translate the + // card mark barrier? It always needs to be translated to a "dmb + // ish" instruction whether or not it occurs as part of a volatile + // put. A StoreLoad barrier is needed after the object put to ensure + // i) visibility to GC threads of the object put and ii) visibility + // to the mutator thread of any card clearing write by a GC + // thread. Clearly a normal store (str) will not guarantee this + // ordering but neither will a releasing store (stlr). The latter + // guarantees that the object put is visible but does not guarantee + // that writes by other threads have also been observed. + // + // So, returning to the task of translating the object put and the + // leading/trailing membar nodes: what do the non-normal node graph + // look like for these 2 special cases? and how can we determine the + // status of a MemBarRelease, StoreX[mo_release] or MemBarVolatile + // in both normal and non-normal cases? // // A CMS GC post-barrier wraps its card write (StoreCM) inside an If // which selects conditonal execution based on the value loaded @@ -1605,117 +1612,91 @@ source %{ // which looks like this // // MemBarRelease - // MemBarCPUOrder_(leading)____________________ - // C | | M \ \\ M | C \ - // | | \ StoreN/P[mo_release] | CastP2X - // | | Bot \ / oop \ | - // | | MergeMem \ / - // | | / | / - // MemBarVolatile (card mark) | / - // C | || M | | / - // | LoadB | Bot oop | / Bot - // | | | / / - // | Cmp |\ / / - // | / | \ / / - // If | \ / / - // | \ | \ / / - // IfFalse IfTrue | \ / / - // \ / \ | | / / - // \ / StoreCM | / / - // \ / \ / / / - // Region Phi / / - // | \ Raw | / / - // | . . . | / / + // MemBarCPUOrder_(leading)__________________ + // C | M \ \\ C \ + // | \ StoreN/P[mo_release] CastP2X + // | Bot \ / + // | MergeMem + // | / + // MemBarVolatile (card mark) + // C | || M | + // | LoadB | + // | | | + // | Cmp |\ + // | / | \ + // If | \ + // | \ | \ + // IfFalse IfTrue | \ + // \ / \ | \ + // \ / StoreCM | + // \ / | | + // Region . . . | + // | \ / + // | . . . \ / Bot // | MergeMem - // | | + // | | // MemBarVolatile (trailing) // - // Notice that there are two MergeMem nodes below the leading - // membar. The first MergeMem merges the AliasIdxBot Mem slice from - // the leading membar and the oopptr Mem slice from the Store into - // the card mark membar. The trailing MergeMem merges the - // AliasIdxBot Mem slice from the leading membar, the AliasIdxRaw - // slice from the StoreCM and an oop slice from the StoreN/P node - // into the trailing membar (n.b. the raw slice proceeds via a Phi - // associated with the If region). + // The first MergeMem merges the AliasIdxBot Mem slice from the + // leading membar and the oopptr Mem slice from the Store into the + // card mark membar. The trailing MergeMem merges the AliasIdxBot + // Mem slice from the card mark membar and the AliasIdxRaw slice + // from the StoreCM into the trailing membar (n.b. the latter + // proceeds via a Phi associated with the If region). // - // So, in the case of CMS + CondCardMark the volatile object store - // graph still includes a normal volatile store subgraph from the - // leading membar to the trailing membar. However, it also contains - // the same shape memory flow to the card mark membar. The two flows - // can be distinguished by testing whether or not the downstream - // membar is a card mark membar. - // - // The graph for a CAS also varies with CMS + CondCardMark, in - // particular employing a control feed from the CompareAndSwapX node - // through a CmpI and If to the card mark membar and StoreCM which - // updates the associated card. This avoids executing the card mark - // if the CAS fails. However, it can be seen from the diagram below - // that the presence of the barrier does not alter the normal CAS - // memory subgraph where the leading membar feeds a CompareAndSwapX, - // an SCMemProj, a MergeMem then a final trailing MemBarCPUOrder and - // MemBarAcquire pair. + // The graph for a CAS varies slightly, the obvious difference being + // that the StoreN/P node is replaced by a CompareAndSwapP/N node + // and the trailing MemBarVolatile by a MemBarCPUOrder + + // MemBarAcquire pair. The other important difference is that the + // CompareAndSwap node's SCMemProj is not merged into the card mark + // membar - it still feeds the trailing MergeMem. This also means + // that the card mark membar receives its Mem feed directly from the + // leading membar rather than via a MergeMem. // // MemBarRelease - // MemBarCPUOrder__(leading)_______________________ - // C / M | \\ C \ - // . . . | Bot CompareAndSwapN/P CastP2X - // | C / M | - // | CmpI | - // | / | - // | . . . | - // | IfTrue | - // | / | - // MemBarVolatile (card mark) | - // C | || M | | - // | LoadB | Bot ______/| - // | | | / | - // | Cmp | / SCMemProj - // | / | / | - // If | / / - // | \ | / / Bot - // IfFalse IfTrue | / / - // | / \ / / prec / - // . . . | / StoreCM / - // \ | / | raw / - // Region . . . / - // | \ / - // | . . . \ / Bot - // | MergeMem - // | / - // MemBarCPUOrder - // MemBarAcquire (trailing) + // MemBarCPUOrder__(leading)_________________________ + // || \\ C \ + // MemBarVolatile (card mark) CompareAndSwapN/P CastP2X + // C | || M | | + // | LoadB | ______/| + // | | | / | + // | Cmp | / SCMemProj + // | / | / | + // If | / / + // | \ | / / + // IfFalse IfTrue | / / + // \ / \ |/ prec / + // \ / StoreCM / + // \ / | / + // Region . . . / + // | \ / + // | . . . \ / Bot + // | MergeMem + // | | + // MemBarCPUOrder + // MemBarAcquire (trailing) // // This has a slightly different memory subgraph to the one seen - // previously but the core of it has a similar memory flow to the - // CAS normal subgraph: + // previously but the core of it is the same as for the CAS normal + // sungraph // // MemBarRelease // MemBarCPUOrder____ - // | \ . . . - // | CompareAndSwapX . . . - // | C / M | - // | CmpI | - // | / | - // | . . / - // Bot | IfTrue / - // | / / - // MemBarVolatile / - // | ... / - // StoreCM ... / - // | / - // . . . SCMemProj - // Raw \ / Bot - // MergeMem - // | + // || \ . . . + // MemBarVolatile CompareAndSwapX . . . + // | \ | + // . . . SCMemProj + // | / . . . + // MergeMem + // | // MemBarCPUOrder // MemBarAcquire // - // The G1 graph for a volatile object put is a lot more complicated. - // Nodes inserted on behalf of G1 may comprise: a pre-write graph - // which adds the old value to the SATB queue; the releasing store - // itself; and, finally, a post-write graph which performs a card - // mark. + // + // G1 is quite a lot more complicated. The nodes inserted on behalf + // of G1 may comprise: a pre-write graph which adds the old value to + // the SATB queue; the releasing store itself; and, finally, a + // post-write graph which performs a card mark. // // The pre-write graph may be omitted, but only when the put is // writing to a newly allocated (young gen) object and then only if @@ -1753,60 +1734,25 @@ source %{ // | CastP2X | StoreN/P[mo_release] | // | | | | // C | M | M | M | - // \ | Raw | oop / Bot + // \ | | / // . . . // (post write subtree elided) // . . . // C \ M / // MemBarVolatile (trailing) // - // Note that the three memory feeds into the post-write tree are an - // AliasRawIdx slice associated with the writes in the pre-write - // tree, an oop type slice from the StoreX specific to the type of - // the volatile field and the AliasBotIdx slice emanating from the - // leading membar. - // // n.b. the LoadB in this subgraph is not the card read -- it's a // read of the SATB queue active flag. // - // The CAS graph is once again a variant of the above with a - // CompareAndSwapX node and SCMemProj in place of the StoreX. The - // value from the CompareAndSwapX node is fed into the post-write - // graph aling with the AliasIdxRaw feed from the pre-barrier and - // the AliasIdxBot feeds from the leading membar and the ScMemProj. - // - // MemBarRelease (leading)____________ - // C | || M \ M \ M \ M \ . . . - // | LoadB \ LoadL LoadN \ - // | / \ \ - // If |\ \ - // | \ | \ \ - // IfFalse IfTrue | \ \ - // | | | \ \ - // | If | \ | - // | | \ | - // | \ | - // | . . . \ | - // | / | / \ | - // Region Phi[M] \ | - // | \ | \ | - // | \_____ | | | - // C | C \ | | | - // | CastP2X | CompareAndSwapX | - // | | res | | | - // C | M | | SCMemProj M | - // \ | Raw | | Bot / Bot - // . . . - // (post write subtree elided) - // . . . - // C \ M / - // MemBarVolatile (trailing) + // Once again the CAS graph is a minor variant on the above with the + // expected substitutions of CompareAndSawpX for StoreN/P and + // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile. // // The G1 post-write subtree is also optional, this time when the // new value being written is either null or can be identified as a // newly allocated (young gen) object with no intervening control // flow. The latter cannot happen but the former may, in which case - // the card mark membar is omitted and the memory feeds from the + // the card mark membar is omitted and the memory feeds form the // leading membar and the SToreN/P are merged direct into the // trailing membar as per the normal subgraph. So, the only special // case which arises is when the post-write subgraph is generated. @@ -1828,106 +1774,94 @@ source %{ // // (pre-write subtree elided) // . . . . . . . . . . . . - // C | M | M | M | - // Region Phi[M] StoreN | - // | Raw | oop | Bot | - // / \_______ |\ |\ |\ - // C / C \ . . . | \ | \ | \ - // If CastP2X . . . | \ | \ | \ - // / \ | \ | \ | \ - // / \ | \ | \ | \ - // IfFalse IfTrue | | | \ - // | | \ | / | - // | If \ | \ / \ | - // | / \ \ | / \ | - // | / \ \ | / \ | | - // | IfFalse IfTrue MergeMem \ | | - // | . . . / \ | \ | | - // | / \ | | | | - // | IfFalse IfTrue | | | | - // | . . . | | | | | - // | If / | | | - // | / \ / | | | - // | / \ / | | | - // | IfFalse IfTrue / | | | - // | . . . | / | | | - // | \ / | | | - // | \ / | | | - // | MemBarVolatile__(card mark ) | | | - // | || C | \ | | | - // | LoadB If | / | | - // | / \ Raw | / / / - // | . . . | / / / - // | \ | / / / - // | StoreCM / / / - // | | / / / - // | . . . / / - // | / / - // | . . . / / - // | | | / / / - // | | Phi[M] / / / - // | | | / / / - // | | | / / / - // | Region . . . Phi[M] / / - // | | | / / - // \ | | / / - // \ | . . . | / / - // \ | | / / - // Region Phi[M] / / - // | \ / / - // \ MergeMem - // \ / - // MemBarVolatile + // C | M | M | M | + // Region Phi[M] StoreN | + // | / \ | | + // / \_______ / \ | | + // C / C \ . . . \ | | + // If CastP2X . . . | | | + // / \ | | | + // / \ | | | + // IfFalse IfTrue | | | + // | | | | /| + // | If | | / | + // | / \ | | / | + // | / \ \ | / | + // | IfFalse IfTrue MergeMem | + // | . . . / \ / | + // | / \ / | + // | IfFalse IfTrue / | + // | . . . | / | + // | If / | + // | / \ / | + // | / \ / | + // | IfFalse IfTrue / | + // | . . . | / | + // | \ / | + // | \ / | + // | MemBarVolatile__(card mark) | + // | || C | M \ M \ | + // | LoadB If | | | + // | / \ | | | + // | . . . | | | + // | \ | | / + // | StoreCM | / + // | . . . | / + // | _________/ / + // | / _____________/ + // | . . . . . . | / / + // | | | / _________/ + // | | Phi[M] / / + // | | | / / + // | | | / / + // | Region . . . Phi[M] _____/ + // | / | / + // | | / + // | . . . . . . | / + // | / | / + // Region | | Phi[M] + // | | | / Bot + // \ MergeMem + // \ / + // MemBarVolatile // - // As with CMS + CondCardMark the first MergeMem merges the - // AliasIdxBot Mem slice from the leading membar and the oopptr Mem - // slice from the Store into the card mark membar. However, in this - // case it may also merge an AliasRawIdx mem slice from the pre - // barrier write. + // As with CMS the initial MergeMem merges the AliasIdxBot Mem slice + // from the leading membar and the oopptr Mem slice from the Store + // into the card mark membar i.e. the memory flow to the card mark + // membar still looks like a normal graph. // - // The trailing MergeMem merges an AliasIdxBot Mem slice from the - // leading membar with an oop slice from the StoreN and an - // AliasRawIdx slice from the post barrier writes. In this case the - // AliasIdxRaw Mem slice is merged through a series of Phi nodes - // which combine feeds from the If regions in the post barrier - // subgraph. + // The trailing MergeMem merges an AliasIdxBot Mem slice with other + // Mem slices (from the StoreCM and other card mark queue stores). + // However in this case the AliasIdxBot Mem slice does not come + // direct from the card mark membar. It is merged through a series + // of Phi nodes. These are needed to merge the AliasIdxBot Mem flow + // from the leading membar with the Mem feed from the card mark + // membar. Each Phi corresponds to one of the Ifs which may skip + // around the card mark membar. So when the If implementing the NULL + // value check has been elided the total number of Phis is 2 + // otherwise it is 3. // - // So, for G1 the same characteristic subgraph arises as for CMS + - // CondCardMark. There is a normal subgraph feeding the card mark - // membar and a normal subgraph feeding the trailing membar. + // The CAS graph when using G1GC also includes a pre-write subgraph + // and an optional post-write subgraph. Teh sam evarioations are + // introduced as for CMS with conditional card marking i.e. the + // StoreP/N is swapped for a CompareAndSwapP/N, the tariling + // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the + // Mem feed from the CompareAndSwapP/N includes a precedence + // dependency feed to the StoreCM and a feed via an SCMemProj to the + // trailing membar. So, as before the configuration includes the + // normal CAS graph as a subgraph of the memory flow. // - // The CAS graph when using G1GC also includes an optional - // post-write subgraph. It is very similar to the above graph except - // for a few details. - // - // - The control flow is gated by an additonal If which tests the - // result from the CompareAndSwapX node - // - // - The MergeMem which feeds the card mark membar only merges the - // AliasIdxBot slice from the leading membar and the AliasIdxRaw - // slice from the pre-barrier. It does not merge the SCMemProj - // AliasIdxBot slice. So, this subgraph does not look like the - // normal CAS subgraph. - // - // - The MergeMem which feeds the trailing membar merges the - // AliasIdxBot slice from the leading membar, the AliasIdxRaw slice - // from the post-barrier and the SCMemProj AliasIdxBot slice i.e. it - // has two AliasIdxBot input slices. However, this subgraph does - // still look like the normal CAS subgraph. - // - // So, the upshot is: - // - // In all cases a volatile put graph will include a *normal* - // volatile store subgraph betwen the leading membar and the - // trailing membar. It may also include a normal volatile store - // subgraph betwen the leading membar and the card mark membar. - // - // In all cases a CAS graph will contain a unique normal CAS graph - // feeding the trailing membar. - // - // In all cases where there is a card mark membar (either as part of - // a volatile object put or CAS) it will be fed by a MergeMem whose - // AliasIdxBot slice feed will be a leading membar. + // So, the upshot is that in all cases the volatile put graph will + // include a *normal* memory subgraph betwen the leading membar and + // its child membar, either a volatile put graph (including a + // releasing StoreX) or a CAS graph (including a CompareAndSwapX). + // When that child is not a card mark membar then it marks the end + // of the volatile put or CAS subgraph. If the child is a card mark + // membar then the normal subgraph will form part of a volatile put + // subgraph if and only if the child feeds an AliasIdxBot Mem feed + // to a trailing barrier via a MergeMem. That feed is either direct + // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier + // memory flow (for G1). // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described @@ -1971,24 +1905,24 @@ source %{ } - // leading_to_trailing + // leading_to_normal // //graph traversal helper which detects the normal case Mem feed from // a release membar (or, optionally, its cpuorder child) to a // dependent volatile membar i.e. it ensures that one or other of // the following Mem flow subgraph is present. // - // MemBarRelease {leading} - // {MemBarCPUOrder} {optional} - // Bot | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {not card mark} + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | StoreN/P[mo_release] . . . + // | / + // MergeMem + // | + // MemBarVolatile {trailing or card mark} // - // MemBarRelease {leading} - // {MemBarCPUOrder} {optional} + // MemBarRelease + // MemBarCPUOrder {leading} // | \ . . . // | CompareAndSwapX . . . // | @@ -1999,23 +1933,6 @@ source %{ // MemBarCPUOrder // MemBarAcquire {trailing} // - // the predicate needs to be capable of distinguishing the following - // volatile put graph which may arises when a GC post barrier - // inserts a card mark membar - // - // MemBarRelease {leading} - // {MemBarCPUOrder}__ - // Bot | \ \ - // | StoreN/P \ - // | / \ | - // MergeMem \ | - // | \ | - // MemBarVolatile \ | - // {card mark} \ | - // MergeMem - // | - // {not card mark} MemBarVolatile - // // if the correct configuration is present returns the trailing // membar otherwise NULL. // @@ -2026,7 +1943,7 @@ source %{ // the returned value may be a card mark or trailing membar // - MemBarNode *leading_to_trailing(MemBarNode *leading) + MemBarNode *leading_to_normal(MemBarNode *leading) { assert((leading->Opcode() == Op_MemBarRelease || leading->Opcode() == Op_MemBarCPUOrder), @@ -2043,21 +1960,15 @@ source %{ StoreNode * st = NULL; LoadStoreNode *cas = NULL; MergeMemNode *mm = NULL; - MergeMemNode *mm2 = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_MergeMem()) { if (mm != NULL) { - if (mm2 != NULL) { - // should not see more than 2 merge mems - return NULL; - } else { - mm2 = x->as_MergeMem(); - } - } else { - mm = x->as_MergeMem(); + return NULL; } + // two merge mems is one too many + mm = x->as_MergeMem(); } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { // two releasing stores/CAS nodes is one too many if (st != NULL || cas != NULL) { @@ -2077,13 +1988,13 @@ source %{ return NULL; } - // must have at least one merge if we also have st + // must have a merge if we also have st if (st && !mm) { return NULL; } + Node *y = NULL; if (cas) { - Node *y = NULL; // look for an SCMemProj for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) { x = cas->fast_out(i); @@ -2103,29 +2014,10 @@ source %{ break; } } - if (mm == NULL) { + if (mm == NULL) return NULL; - } - MemBarNode *mbar = NULL; - // ensure the merge feeds a trailing membar cpuorder + acquire pair - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarCPUOrder) { - MemBarNode *z = x->as_MemBar(); - z = child_membar(z); - if (z != NULL && z->Opcode() == Op_MemBarAcquire) { - mbar = z; - } - } - break; - } - } - return mbar; } else { - Node *y = NULL; - // ensure the store feeds the first mergemem; + // ensure the store feeds the existing mergemem; for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { if (st->fast_out(i) == mm) { y = st; @@ -2135,89 +2027,55 @@ source %{ if (y == NULL) { return NULL; } - if (mm2 != NULL) { - // ensure the store feeds the second mergemem; - y = NULL; - for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { - if (st->fast_out(i) == mm2) { - y = st; - } - } - if (y == NULL) { - return NULL; - } - } + } - MemBarNode *mbar = NULL; - // ensure the first mergemem feeds a volatile membar - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarVolatile) { - mbar = x->as_MemBar(); + MemBarNode *mbar = NULL; + // ensure the merge feeds to the expected type of membar + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile && st) { + mbar = x->as_MemBar(); + } else if (cas && opcode == Op_MemBarCPUOrder) { + MemBarNode *y = x->as_MemBar(); + y = child_membar(y); + if (y != NULL && y->Opcode() == Op_MemBarAcquire) { + mbar = y; } - break; - } - } - if (mm2 == NULL) { - // this is our only option for a trailing membar - return mbar; - } - // ensure the second mergemem feeds a volatile membar - MemBarNode *mbar2 = NULL; - for (DUIterator_Fast imax, i = mm2->fast_outs(imax); i < imax; i++) { - x = mm2->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarVolatile) { - mbar2 = x->as_MemBar(); - } - break; - } - } - // if we have two merge mems we must have two volatile membars - if (mbar == NULL || mbar2 == NULL) { - return NULL; - } - // return the trailing membar - if (is_card_mark_membar(mbar2)) { - return mbar; - } else { - if (is_card_mark_membar(mbar)) { - return mbar2; - } else { - return NULL; } + break; } } + + return mbar; } - // trailing_to_leading + // normal_to_leading // // graph traversal helper which detects the normal case Mem feed - // from a trailing membar to a preceding release membar (optionally - // its cpuorder child) i.e. it ensures that one or other of the - // following Mem flow subgraphs is present. + // from either a card mark or a trailing membar to a preceding + // release membar (optionally its cpuorder child) i.e. it ensures + // that one or other of the following Mem flow subgraphs is present. // - // MemBarRelease {leading} - // MemBarCPUOrder {optional} - // | Bot | \ . . . - // | | StoreN/P[mo_release] . . . - // | | / - // | MergeMem - // | | - // MemBarVolatile {not card mark} + // MemBarRelease + // MemBarCPUOrder {leading} + // | \ . . . + // | StoreN/P[mo_release] . . . + // | / + // MergeMem + // | + // MemBarVolatile {card mark or trailing} // - // MemBarRelease {leading} - // MemBarCPUOrder {optional} + // MemBarRelease + // MemBarCPUOrder {leading} // | \ . . . // | CompareAndSwapX . . . // | // . . . SCMemProj // \ | // | MergeMem - // | | + // | / // MemBarCPUOrder // MemBarAcquire {trailing} // @@ -2227,20 +2085,15 @@ source %{ // if the configuration is present returns the cpuorder member for // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a MemBarVolatile or - // MemBarAcquire. if it is a MemBarVolatile it must *not* be a card - // mark membar. + // n.b. the input membar is expected to be a MemBarVolatile but + // need not be a card mark membar. - MemBarNode *trailing_to_leading(const MemBarNode *barrier) + MemBarNode *normal_to_leading(const MemBarNode *barrier) { // input must be a volatile membar assert((barrier->Opcode() == Op_MemBarVolatile || barrier->Opcode() == Op_MemBarAcquire), "expecting a volatile or an acquire membar"); - - assert((barrier->Opcode() != Op_MemBarVolatile) || - !is_card_mark_membar(barrier), - "not expecting a card mark membar"); Node *x; bool is_cas = barrier->Opcode() == Op_MemBarAcquire; @@ -2353,35 +2206,169 @@ source %{ return NULL; } - // card_mark_to_leading + // card_mark_to_trailing // - // graph traversal helper which traverses from a card mark volatile - // membar to a leading membar i.e. it ensures that the following Mem - // flow subgraph is present. + // graph traversal helper which detects extra, non-normal Mem feed + // from a card mark volatile membar to a trailing membar i.e. it + // ensures that one of the following three GC post-write Mem flow + // subgraphs is present. // - // MemBarRelease {leading} - // {MemBarCPUOrder} {optional} - // | . . . + // 1) + // . . . + // | + // MemBarVolatile (card mark) + // | | + // | StoreCM + // | | + // | . . . + // Bot | / + // MergeMem + // | + // | + // MemBarVolatile {trailing} + // + // 2) + // MemBarRelease/CPUOrder (leading) + // | + // | + // |\ . . . + // | \ | + // | \ MemBarVolatile (card mark) + // | \ | | + // \ \ | StoreCM . . . + // \ \ | + // \ Phi + // \ / + // Phi . . . // Bot | / - // MergeMem + // MergeMem // | - // MemBarVolatile (card mark) - // | \ - // . . . StoreCM + // MemBarVolatile {trailing} // - // if the configuration is present returns the cpuorder member for - // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a MemBarVolatile amd must - // be a card mark membar. + // 3) + // MemBarRelease/CPUOrder (leading) + // | + // |\ + // | \ + // | \ . . . + // | \ | + // |\ \ MemBarVolatile (card mark) + // | \ \ | | + // | \ \ | StoreCM . . . + // | \ \ | + // \ \ Phi + // \ \ / + // \ Phi + // \ / + // Phi . . . + // Bot | / + // MergeMem + // | + // | + // MemBarVolatile {trailing} + // + // configuration 1 is only valid if UseConcMarkSweepGC && + // UseCondCardMark + // + // configurations 2 and 3 are only valid if UseG1GC. + // + // if a valid configuration is present returns the trailing membar + // otherwise NULL. + // + // n.b. the supplied membar is expected to be a card mark + // MemBarVolatile i.e. the caller must ensure the input node has the + // correct operand and feeds Mem to a StoreCM node - MemBarNode *card_mark_to_leading(const MemBarNode *barrier) + MemBarNode *card_mark_to_trailing(const MemBarNode *barrier) { // input must be a card mark volatile membar assert(is_card_mark_membar(barrier), "expecting a card mark membar"); + Node *feed = barrier->proj_out(TypeFunc::Memory); + Node *x; + MergeMemNode *mm = NULL; + + const int MAX_PHIS = 3; // max phis we will search through + int phicount = 0; // current search count + + bool retry_feed = true; + while (retry_feed) { + // see if we have a direct MergeMem feed + for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { + x = feed->fast_out(i); + // the correct Phi will be merging a Bot memory slice + if (x->is_MergeMem()) { + mm = x->as_MergeMem(); + break; + } + } + if (mm) { + retry_feed = false; + } else if (UseG1GC & phicount++ < MAX_PHIS) { + // the barrier may feed indirectly via one or two Phi nodes + PhiNode *phi = NULL; + for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { + x = feed->fast_out(i); + // the correct Phi will be merging a Bot memory slice + if (x->is_Phi() && x->adr_type() == TypePtr::BOTTOM) { + phi = x->as_Phi(); + break; + } + } + if (!phi) { + return NULL; + } + // look for another merge below this phi + feed = phi; + } else { + // couldn't find a merge + return NULL; + } + } + + // sanity check this feed turns up as the expected slice + assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge"); + + MemBarNode *trailing = NULL; + // be sure we have a trailing membar the merge + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { + trailing = x->as_MemBar(); + break; + } + } + + return trailing; + } + + // trailing_to_card_mark + // + // graph traversal helper which detects extra, non-normal Mem feed + // from a trailing volatile membar to a preceding card mark volatile + // membar i.e. it identifies whether one of the three possible extra + // GC post-write Mem flow subgraphs is present + // + // this predicate checks for the same flow as the previous predicate + // but starting from the bottom rather than the top. + // + // if the configuration is present returns the card mark membar + // otherwise NULL + // + // n.b. the supplied membar is expected to be a trailing + // MemBarVolatile i.e. the caller must ensure the input node has the + // correct opcode + + MemBarNode *trailing_to_card_mark(const MemBarNode *trailing) + { + assert(trailing->Opcode() == Op_MemBarVolatile, + "expecting a volatile membar"); + assert(!is_card_mark_membar(trailing), + "not expecting a card mark membar"); + // the Mem feed to the membar should be a merge - Node *x = barrier->in(TypeFunc::Memory); + Node *x = trailing->in(TypeFunc::Memory); if (!x->is_MergeMem()) { return NULL; } @@ -2389,20 +2376,118 @@ source %{ MergeMemNode *mm = x->as_MergeMem(); x = mm->in(Compile::AliasIdxBot); + // with G1 we may possibly see a Phi or two before we see a Memory + // Proj from the card mark membar + const int MAX_PHIS = 3; // max phis we will search through + int phicount = 0; // current search count + + bool retry_feed = !x->is_Proj(); + + while (retry_feed) { + if (UseG1GC && x->is_Phi() && phicount++ < MAX_PHIS) { + PhiNode *phi = x->as_Phi(); + ProjNode *proj = NULL; + PhiNode *nextphi = NULL; + bool found_leading = false; + for (uint i = 1; i < phi->req(); i++) { + x = phi->in(i); + if (x->is_Phi()) { + nextphi = x->as_Phi(); + } else if (x->is_Proj()) { + int opcode = x->in(0)->Opcode(); + if (opcode == Op_MemBarVolatile) { + proj = x->as_Proj(); + } else if (opcode == Op_MemBarRelease || + opcode == Op_MemBarCPUOrder) { + // probably a leading membar + found_leading = true; + } + } + } + // if we found a correct looking proj then retry from there + // otherwise we must see a leading and a phi or this the + // wrong config + if (proj != NULL) { + x = proj; + retry_feed = false; + } else if (found_leading && nextphi != NULL) { + // retry from this phi to check phi2 + x = nextphi; + } else { + // not what we were looking for + return NULL; + } + } else { + return NULL; + } + } + // the proj has to come from the card mark membar + x = x->in(0); if (!x->is_MemBar()) { return NULL; } - MemBarNode *leading = x->as_MemBar(); + MemBarNode *card_mark_membar = x->as_MemBar(); - if (leading_membar(leading)) { + if (!is_card_mark_membar(card_mark_membar)) { + return NULL; + } + + return card_mark_membar; + } + + // trailing_to_leading + // + // graph traversal helper which checks the Mem flow up the graph + // from a (non-card mark) trailing membar attempting to locate and + // return an associated leading membar. it first looks for a + // subgraph in the normal configuration (relying on helper + // normal_to_leading). failing that it then looks for one of the + // possible post-write card mark subgraphs linking the trailing node + // to a the card mark membar (relying on helper + // trailing_to_card_mark), and then checks that the card mark membar + // is fed by a leading membar (once again relying on auxiliary + // predicate normal_to_leading). + // + // if the configuration is valid returns the cpuorder member for + // preference or when absent the release membar otherwise NULL. + // + // n.b. the input membar is expected to be either a volatile or + // acquire membar but in the former case must *not* be a card mark + // membar. + + MemBarNode *trailing_to_leading(const MemBarNode *trailing) + { + assert((trailing->Opcode() == Op_MemBarAcquire || + trailing->Opcode() == Op_MemBarVolatile), + "expecting an acquire or volatile membar"); + assert((trailing->Opcode() != Op_MemBarVolatile || + !is_card_mark_membar(trailing)), + "not expecting a card mark membar"); + + MemBarNode *leading = normal_to_leading(trailing); + + if (leading) { return leading; } - return NULL; + // nothing more to do if this is an acquire + if (trailing->Opcode() == Op_MemBarAcquire) { + return NULL; + } + + MemBarNode *card_mark_membar = trailing_to_card_mark(trailing); + + if (!card_mark_membar) { + return NULL; + } + + return normal_to_leading(card_mark_membar); } + // predicates controlling emit of ldr/ldar and associated dmb + bool unnecessary_acquire(const Node *barrier) { assert(barrier->is_MemBar(), "expecting a membar"); @@ -2617,8 +2702,19 @@ bool unnecessary_release(const Node *n) } // must start with a normal feed - MemBarNode *trailing = leading_to_trailing(barrier); + MemBarNode *child_barrier = leading_to_normal(barrier); + if (!child_barrier) { + return false; + } + + if (!is_card_mark_membar(child_barrier)) { + // this is the trailing membar and we are done + return true; + } + + // must be sure this card mark feeds a trailing membar + MemBarNode *trailing = card_mark_to_trailing(child_barrier); return (trailing != NULL); } @@ -2640,7 +2736,7 @@ bool unnecessary_volatile(const Node *n) } // ok, if it's not a card mark then we still need to check if it is - // a trailing membar of a volatile put graph. + // a trailing membar of a volatile put hgraph. return (trailing_to_leading(mbvol) != NULL); } @@ -2690,9 +2786,20 @@ bool needs_releasing_store(const Node *n) } // does this lead a normal subgraph? - MemBarNode *trailing = leading_to_trailing(barrier); + MemBarNode *mbvol = leading_to_normal(barrier); - return (trailing != NULL); + if (!mbvol) { + return false; + } + + // all done unless this is a card mark + if (!is_card_mark_membar(mbvol)) { + return true; + } + + // we found a card mark -- just make sure we have a trailing barrier + + return (card_mark_to_trailing(mbvol) != NULL); } // predicate controlling translation of CAS @@ -2734,7 +2841,7 @@ bool needs_acquiring_load_exclusive(const Node *n) "CAS not fed by cpuorder+release membar pair!"); // does this lead a normal subgraph? - MemBarNode *mbar = leading_to_trailing(barrier); + MemBarNode *mbar = leading_to_normal(barrier); assert(mbar != NULL, "CAS not embedded in normal graph!"); @@ -2755,27 +2862,48 @@ bool unnecessary_storestore(const Node *storecm) // we only ever need to generate a dmb ishst between an object put // and the associated card mark when we are using CMS without - // conditional card marking. Any other occurence will happen when - // performing a card mark using CMS with conditional card marking or - // G1. In those cases the preceding MamBarVolatile will be - // translated to a dmb ish which guarantes visibility of the - // preceding StoreN/P before this StoreCM + // conditional card marking if (!UseConcMarkSweepGC || UseCondCardMark) { return true; } - // if we are implementing volatile puts using barriers then we must - // insert the dmb ishst + // if we are implementing volatile puts using barriers then the + // object put as an str so we must insert the dmb ishst if (UseBarriersForVolatile) { return false; } - // we must be using CMS with conditional card marking so we ahve to - // generate the StoreStore + // we can omit the dmb ishst if this StoreCM is part of a volatile + // put because in thta case the put will be implemented by stlr + // + // we need to check for a normal subgraph feeding this StoreCM. + // that means the StoreCM must be fed Memory from a leading membar, + // either a MemBarRelease or its dependent MemBarCPUOrder, and the + // leading membar must be part of a normal subgraph - return false; + Node *x = storecm->in(StoreNode::Memory); + + if (!x->is_Proj()) { + return false; + } + + x = x->in(0); + + if (!x->is_MemBar()) { + return false; + } + + MemBarNode *leading = x->as_MemBar(); + + // reject invalid candidates + if (!leading_membar(leading)) { + return false; + } + + // we can omit the StoreStore if it is the head of a normal subgraph + return (leading_to_normal(leading) != NULL); } @@ -3008,6 +3136,10 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ notify(Assembler::method_reentry); } + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + if (do_polling() && C->is_method_compilation()) { __ read_polling_page(rscratch1, os::get_polling_page(), relocInfo::poll_return_type); } @@ -9862,7 +9994,7 @@ instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne // END This section of the file is automatically generated. Do not edit -------------- // --------------------------------------------------------------------- -instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{ +instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) %{ match(Set prev (GetAndSetI mem newv)); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} ins_encode %{ @@ -9871,7 +10003,7 @@ instruct get_and_setI(indirect mem, iRegINoSp newv, iRegI prev) %{ ins_pipe(pipe_serial); %} -instruct get_and_setL(indirect mem, iRegLNoSp newv, iRegL prev) %{ +instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{ match(Set prev (GetAndSetL mem newv)); format %{ "atomic_xchg $prev, $newv, [$mem]" %} ins_encode %{ @@ -9880,7 +10012,7 @@ instruct get_and_setL(indirect mem, iRegLNoSp newv, iRegL prev) %{ ins_pipe(pipe_serial); %} -instruct get_and_setN(indirect mem, iRegNNoSp newv, iRegI prev) %{ +instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ match(Set prev (GetAndSetN mem newv)); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} ins_encode %{ @@ -9889,7 +10021,7 @@ instruct get_and_setN(indirect mem, iRegNNoSp newv, iRegI prev) %{ ins_pipe(pipe_serial); %} -instruct get_and_setP(indirect mem, iRegPNoSp newv, iRegP prev) %{ +instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) %{ match(Set prev (GetAndSetP mem newv)); format %{ "atomic_xchg $prev, $newv, [$mem]" %} ins_encode %{ diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp index 70c8f909337..b139a44f9a1 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp @@ -532,8 +532,14 @@ void LIR_Assembler::poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* void LIR_Assembler::return_op(LIR_Opr result) { assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,"); + // Pop the stack before the safepoint code __ remove_frame(initial_frame_size_in_bytes()); + + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + address polling_page(os::get_polling_page()); __ read_polling_page(rscratch1, polling_page, relocInfo::poll_return_type); __ ret(lr); diff --git a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp index 58ba9c0b613..8c83dc4125c 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_Runtime1_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1179,6 +1179,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ldrw(tmp, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(tmp, in_progress); + } + __ cbzw(tmp, done); + // Can we store original value in the thread's buffer? __ ldr(tmp, queue_index); __ cbz(tmp, runtime); diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp index b74bce2d415..fe48df281b1 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp @@ -375,7 +375,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp fr._unextended_sp = unextended_sp; address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); } #endif @@ -629,6 +630,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) { DESCRIBE_FP_OFFSET(interpreter_frame_last_sp); DESCRIBE_FP_OFFSET(interpreter_frame_method); DESCRIBE_FP_OFFSET(interpreter_frame_mdp); + DESCRIBE_FP_OFFSET(interpreter_frame_mirror); DESCRIBE_FP_OFFSET(interpreter_frame_cache); DESCRIBE_FP_OFFSET(interpreter_frame_locals); DESCRIBE_FP_OFFSET(interpreter_frame_bcp); diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp index 5bcee325945..64a35bd3c30 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.hpp @@ -46,6 +46,9 @@ // [pointer to locals ] = locals() locals_offset // [constant pool cache ] = cache() cache_offset +// [klass of method ] = mirror() mirror_offset +// [padding ] + // [methodData ] = mdp() mdx_offset // [methodOop ] = method() method_offset diff --git a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp index 7c410aaa74b..4f6d2bef7f5 100644 --- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp +++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.inline.hpp @@ -82,7 +82,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; - assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod"); + assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { _deopt_state = not_deoptimized; diff --git a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp index 4c9d377ff09..0d78e2da1fe 100644 --- a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp @@ -53,4 +53,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false; // evidence that it's worth doing. #define DEOPTIMIZE_WHEN_PATCHING +#define SUPPORT_RESERVED_STACK_AREA + #endif // CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP diff --git a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp index 926e06004dc..06ec817cd9b 100644 --- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp @@ -50,7 +50,7 @@ define_pd_global(intx, InlineFrequencyCount, 100); // stack if compiled for unix and LP64. To pass stack overflow tests we need // 20 shadow pages. #define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+5)) -#define DEFAULT_STACK_RESERVED_PAGES (0) +#define DEFAULT_STACK_RESERVED_PAGES (1) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp index ed95d410e36..81636fb8ea1 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp @@ -619,6 +619,22 @@ void InterpreterMacroAssembler::remove_activation( // get sender esp ldr(esp, Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); + if (StackReservedPages > 0) { + // testing if reserved zone needs to be re-enabled + Label no_reserved_zone_enabling; + + ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset())); + cmp(esp, rscratch1); + br(Assembler::LS, no_reserved_zone_enabling); + + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_delayed_StackOverflowError)); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } // remove frame anchor leave(); // If we're returning to interpreted code we will shortly be diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index dc90886ab68..1c955d5afe3 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -402,6 +402,30 @@ void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) { } } +void MacroAssembler::reserved_stack_check() { + // testing if reserved zone needs to be enabled + Label no_reserved_zone_enabling; + + ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset())); + cmp(sp, rscratch1); + br(Assembler::LO, no_reserved_zone_enabling); + + enter(); // LR and FP are live. + lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)); + mov(c_rarg0, rthread); + blr(rscratch1); + leave(); + + // We have already removed our own frame. + // throw_delayed_StackOverflowError will think that it's been + // called by our caller. + lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry())); + br(rscratch1); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); +} + int MacroAssembler::biased_locking_enter(Register lock_reg, Register obj_reg, Register swap_reg, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 3418189f1b4..2f17699a262 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -957,6 +957,9 @@ public: // stack overflow + shadow pages. Also, clobbers tmp void bang_stack_size(Register size, Register tmp); + // Check for reserved stack access in method being exited (for JIT) + void reserved_stack_check(); + virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset); diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 681ecf34277..3143fe97d88 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -4676,8 +4676,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, - SharedRuntime:: - throw_StackOverflowError)); + SharedRuntime::throw_StackOverflowError)); + StubRoutines::_throw_delayed_StackOverflowError_entry = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime::throw_delayed_StackOverflowError)); if (UseCRC32Intrinsics) { // set table address before stub generation which use it StubRoutines::_crc_table_adr = (address)StubRoutines::aarch64::_crc_table; diff --git a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp index 937dfe91242..9f17c8fc810 100644 --- a/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp +++ b/hotspot/src/cpu/arm/vm/c1_Runtime1_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -551,6 +551,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { const Register r_index_1 = R1; const Register r_buffer_2 = R2; + Address queue_active(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index())); Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() + @@ -559,6 +561,11 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(R1, queue_active); + __ cbz(R1, done); + __ ldr(r_index_1, queue_index); __ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize)); __ ldr(r_buffer_2, buffer); diff --git a/hotspot/src/cpu/arm/vm/frame_arm.cpp b/hotspot/src/cpu/arm/vm/frame_arm.cpp index 55f468fa74c..defe4a45a4a 100644 --- a/hotspot/src/cpu/arm/vm/frame_arm.cpp +++ b/hotspot/src/cpu/arm/vm/frame_arm.cpp @@ -364,7 +364,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp fr._unextended_sp = unextended_sp; address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains(original_pc), "original PC must be in nmethod"); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be"); } #endif diff --git a/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp index 589d75be640..4bde8e7be08 100644 --- a/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp +++ b/hotspot/src/cpu/arm/vm/frame_arm.inline.hpp @@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; - assert(_cb->as_compiled_method()->insts_contains(_pc), "original PC must be in CompiledMethod"); + assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { _deopt_state = not_deoptimized; diff --git a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp index 1aa158b4a8f..3562a79825f 100644 --- a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -741,7 +741,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp = R14; Register tmp2 = R15; - Label refill, restart; + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -753,6 +756,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ std(tmp, -16, R1_SP); __ std(tmp2, -24, R1_SP); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwz(tmp, satb_q_active_byte_offset, R16_thread); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(tmp, satb_q_active_byte_offset, R16_thread); + } + __ cmpdi(CCR0, tmp, 0); + __ beq(CCR0, marking_not_active); + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate. @@ -769,6 +782,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ std(tmp, satb_q_index_byte_offset, R16_thread); __ stdx(pre_val, tmp2, tmp); // [_buf + index] := + __ bind(marking_not_active); // Restore temp registers and return-from-leaf. __ ld(tmp2, -24, R1_SP); __ ld(tmp, -16, R1_SP); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 2d1f0c7230b..a5d5613a414 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -2569,7 +2569,7 @@ void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register } // Spin and retry if lock is busy. -// inputs: box_Reg (monitor address) +// inputs: owner_addr_Reg (monitor address) // : retry_count_Reg // output: retry_count_Reg decremented by 1 // CTR is killed @@ -2577,15 +2577,22 @@ void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register o Label SpinLoop, doneRetry; addic_(retry_count_Reg, retry_count_Reg, -1); blt(CCR0, doneRetry); - li(R0, RTMSpinLoopCount); - mtctr(R0); + + if (RTMSpinLoopCount > 1) { + li(R0, RTMSpinLoopCount); + mtctr(R0); + } bind(SpinLoop); smt_yield(); // Can't use waitrsv(). No permission (SIGILL). - bdz(retryLabel); - ld(R0, 0, owner_addr_Reg); - cmpdi(CCR0, R0, 0); - bne(CCR0, SpinLoop); + + if (RTMSpinLoopCount > 1) { + bdz(retryLabel); + ld(R0, 0, owner_addr_Reg); + cmpdi(CCR0, R0, 0); + bne(CCR0, SpinLoop); + } + b(retryLabel); bind(doneRetry); diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 6c6b83d257f..5e8be1425fa 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -327,7 +327,10 @@ void VM_Version::initialize() { warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50"); FLAG_SET_DEFAULT(RTMAbortRatio, 50); } - guarantee(RTMSpinLoopCount > 0, "unsupported"); + if (RTMSpinLoopCount < 0) { + warning("RTMSpinLoopCount must not be a negative value, resetting it to 0"); + FLAG_SET_DEFAULT(RTMSpinLoopCount, 0); + } #else // Only C2 does RTM locking optimization. // Can't continue because UseRTMLocking affects UseBiasedLocking flag diff --git a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp index 524a91fe07f..84fb4205099 100644 --- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp @@ -1105,16 +1105,16 @@ void LIR_Assembler::reg2mem(LIR_Opr from, LIR_Opr dest_opr, BasicType type, } case T_FLOAT : if (short_disp) { - __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest); + __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest); } else { - __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest); + __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest); } break; case T_DOUBLE: if (short_disp) { - __ z_std(from->as_double_reg(), disp_value, disp_reg, dest); + __ z_std(from->as_double_reg(), disp_value, disp_reg, dest); } else { - __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest); + __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest); } break; default: ShouldNotReachHere(); @@ -1148,6 +1148,10 @@ void LIR_Assembler::return_op(LIR_Opr result) { __ restore_return_pc(); } + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(Z_R14); + } + // We need to mark the code position where the load from the safepoint // polling page was emitted as relocInfo::poll_return_type here. __ relocate(relocInfo::poll_return_type); diff --git a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp index c0fbee53da7..7b65476212f 100644 --- a/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp +++ b/hotspot/src/cpu/s390/vm/c1_Runtime1_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -784,7 +784,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val. Register tmp2 = Z_R7; - Label refill, restart; + Label refill, restart, marking_not_active; + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -796,6 +799,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); __ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset)); + } + __ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently. + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate. @@ -810,6 +822,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { __ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := __ z_stg(tmp, satb_q_index_byte_offset, Z_thread); + __ bind(marking_not_active); // Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()). __ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); __ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP); diff --git a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp index 83261cfdf47..63a9cb5abef 100644 --- a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp +++ b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp @@ -52,4 +52,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true; // The expected size in bytes of a cache line, used to pad data structures. #define DEFAULT_CACHE_LINE_SIZE 256 +#define SUPPORT_RESERVED_STACK_AREA + #endif // CPU_S390_VM_GLOBALDEFINITIONS_S390_HPP diff --git a/hotspot/src/cpu/s390/vm/globals_s390.hpp b/hotspot/src/cpu/s390/vm/globals_s390.hpp index fcd3ff45227..cb5adff3ef5 100644 --- a/hotspot/src/cpu/s390/vm/globals_s390.hpp +++ b/hotspot/src/cpu/s390/vm/globals_s390.hpp @@ -56,7 +56,7 @@ define_pd_global(intx, InlineSmallCode, 2000); // Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the // stack. To pass stack overflow tests we need 20 shadow pages. #define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2)) -#define DEFAULT_STACK_RESERVED_PAGES (0) +#define DEFAULT_STACK_RESERVED_PAGES (1) #define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES diff --git a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp index c53fa419a27..8cec2da25ac 100644 --- a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp +++ b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp @@ -860,16 +860,39 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bool throw_monitor_exception, bool install_monitor_exception, bool notify_jvmti) { - + BLOCK_COMMENT("remove_activation {"); unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); // Save result (push state before jvmti call and pop it afterwards) and notify jvmti. notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI); + if (StackReservedPages > 0) { + BLOCK_COMMENT("reserved_stack_check:"); + // Test if reserved zone needs to be enabled. + Label no_reserved_zone_enabling; + + // Compare frame pointers. There is no good stack pointer, as with stack + // frame compression we can get different SPs when we do calls. A subsequent + // call could have a smaller SP, so that this compare succeeds for an + // inner call of the method annotated with ReservedStack. + z_lg(Z_R0, Address(Z_SP, (intptr_t)_z_abi(callers_sp))); + z_clg(Z_R0, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); // Compare with frame pointer in memory. + z_brl(no_reserved_zone_enabling); + + // Enable reserved zone again, throw stack overflow exception. + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread); + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError)); + + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } + verify_oop(Z_tos, state); verify_thread(); pop_interpreter_frame(return_pc, Z_ARG2, Z_ARG3); + BLOCK_COMMENT("} remove_activation"); } // lock object diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp index a7cbd706255..0f78e5a6250 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp @@ -2666,6 +2666,32 @@ void MacroAssembler::bang_stack_with_offset(int offset) { } } +void MacroAssembler::reserved_stack_check(Register return_pc) { + // Test if reserved zone needs to be enabled. + Label no_reserved_zone_enabling; + assert(return_pc == Z_R14, "Return pc must be in R14 before z_br() to StackOverflow stub."); + BLOCK_COMMENT("reserved_stack_check {"); + + z_clg(Z_SP, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); + z_brl(no_reserved_zone_enabling); + + // Enable reserved zone again, throw stack overflow exception. + save_return_pc(); + push_frame_abi160(0); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread); + pop_frame(); + restore_return_pc(); + + load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry()); + // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc. + z_br(Z_R1); + + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + BLOCK_COMMENT("} reserved_stack_check"); +} + // Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes. void MacroAssembler::tlab_allocate(Register obj, Register var_size_in_bytes, diff --git a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp index c9540860958..588bde6207e 100644 --- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp +++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp @@ -627,6 +627,11 @@ class MacroAssembler: public Assembler { // Stack overflow checking void bang_stack_with_offset(int offset); + // Check for reserved stack access in method being exited. If the reserved + // stack area was accessed, protect it again and throw StackOverflowError. + // Uses Z_R1. + void reserved_stack_check(Register return_pc); + // Atomics // -- none? diff --git a/hotspot/src/cpu/s390/vm/s390.ad b/hotspot/src/cpu/s390/vm/s390.ad index 8ab6a5026d3..fd188525c46 100644 --- a/hotspot/src/cpu/s390/vm/s390.ad +++ b/hotspot/src/cpu/s390/vm/s390.ad @@ -909,15 +909,8 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { // If this does safepoint polling, then do it here. bool need_polling = do_polling() && C->is_method_compilation(); - // Touch the polling page. - // Part 1: get the page's address. - if (need_polling) { - AddressLiteral pp(os::get_polling_page()); - __ load_const_optimized(Z_R1_scratch, pp); - } - // Pop frame, restore return_pc, and all stuff needed by interpreter. - // Pop frame by add insted of load (a penny saved is a penny got :-). + // Pop frame by add instead of load (a penny saved is a penny got :-). int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes); int retPC_offset = frame_size_in_bytes + _z_abi16(return_pc); if (Displacement::is_validDisp(retPC_offset)) { @@ -928,9 +921,14 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { __ restore_return_pc(); } - // Touch the polling page, - // part 2: touch the page now. + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(Z_R14); + } + + // Touch the polling page. if (need_polling) { + AddressLiteral pp(os::get_polling_page()); + __ load_const_optimized(Z_R1_scratch, pp); // We need to mark the code position where the load from the safepoint // polling page was emitted as relocInfo::poll_return_type here. __ relocate(relocInfo::poll_return_type); @@ -939,7 +937,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { - // variable size. determine dynamically. + // Variable size. determine dynamically. return MachNode::size(ra_); } diff --git a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp index 8b872c5c922..be107222636 100644 --- a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp @@ -2433,13 +2433,12 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_throw_StackOverflowError_entry = generate_throw_exception("StackOverflowError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); + StubRoutines::_throw_delayed_StackOverflowError_entry = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false); //---------------------------------------------------------------------- // Entry points that are platform specific. - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false); if (UseCRC32Intrinsics) { // We have no CRC32 table on z/Architecture. diff --git a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp index de266db04fc..2084f36006f 100644 --- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp +++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp @@ -1112,16 +1112,21 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state __ add2reg(top_frame_size, frame::z_top_ijava_frame_abi_size + - frame::z_ijava_state_size + - frame::interpreter_frame_monitor_size() * wordSize, + frame::z_ijava_state_size + + frame::interpreter_frame_monitor_size() * wordSize, max_stack); - // Check if there's room for the new frame... - Register frame_size = max_stack; // Reuse the regiser for max_stack. - __ z_lgr(frame_size, Z_SP); - __ z_sgr(frame_size, sp_after_resize); - __ z_agr(frame_size, top_frame_size); - generate_stack_overflow_check(frame_size, fp/*tmp1*/); + if (!native_call) { + // Stack overflow check. + // Native calls don't need the stack size check since they have no + // expression stack and the arguments are already on the stack and + // we only add a handful of words to the stack. + Register frame_size = max_stack; // Reuse the regiser for max_stack. + __ z_lgr(frame_size, Z_SP); + __ z_sgr(frame_size, sp_after_resize); + __ z_agr(frame_size, top_frame_size); + generate_stack_overflow_check(frame_size, fp/*tmp1*/); + } DEBUG_ONLY(__ z_cg(Z_R14, _z_abi16(return_pc), Z_SP)); __ asm_assert_eq("killed Z_R14", 0); diff --git a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp index 97fb2745a26..ae2942f19b5 100644 --- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -694,6 +694,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) { int store_offset; if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) { + assert(base != O7, "destroying register"); assert(!unaligned, "can't handle this"); // for offsets larger than a simm13 we setup the offset in O7 __ set(offset, O7); @@ -712,9 +713,12 @@ int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType case T_LONG : #ifdef _LP64 if (unaligned || PatchALot) { - __ srax(from_reg->as_register_lo(), 32, O7); + // Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem) + assert(G3_scratch != base, "can't handle this"); + assert(G3_scratch != from_reg->as_register_lo(), "can't handle this"); + __ srax(from_reg->as_register_lo(), 32, G3_scratch); __ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes); - __ stw(O7, base, offset + hi_word_offset_in_bytes); + __ stw(G3_scratch, base, offset + hi_word_offset_in_bytes); } else { __ stx(from_reg->as_register_lo(), base, offset); } @@ -821,7 +825,7 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break; case T_INT : __ ld(base, offset, to_reg->as_register()); break; case T_LONG : - if (!unaligned) { + if (!unaligned && !PatchALot) { #ifdef _LP64 __ ldx(base, offset, to_reg->as_register_lo()); #else @@ -1297,7 +1301,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, disp_reg = O7; } } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_register(), O7); + __ add(src, addr->index()->as_pointer_register(), O7); src = O7; } else { disp_reg = addr->index()->as_pointer_register(); @@ -1424,7 +1428,7 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, disp_reg = O7; } } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_register(), O7); + __ add(src, addr->index()->as_pointer_register(), O7); src = O7; } else { disp_reg = addr->index()->as_pointer_register(); diff --git a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp index 5530a85cb4c..40e30551967 100644 --- a/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/c1_Runtime1_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -856,7 +856,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Register tmp2 = G3_scratch; Label refill, restart; - bool with_frame = false; // I don't know if we can do with-frame. + int satb_q_active_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active()); int satb_q_index_byte_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()); @@ -864,6 +866,17 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf()); + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ld(G2_thread, satb_q_active_byte_offset, tmp); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldsb(G2_thread, satb_q_active_byte_offset, tmp); + } + __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart); + __ retl(); + __ delayed()->nop(); + __ bind(restart); // Load the index into the SATB buffer. SATBMarkQueue::_index is a // size_t so ld_ptr is appropriate diff --git a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp index 5fe455600d1..58db92dcd32 100644 --- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1623,6 +1623,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { NOT_LP64(__ get_thread(thread);) + Address queue_active(thread, in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_active())); Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index())); Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() + @@ -1631,6 +1633,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { Label done; Label runtime; + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ cmpl(queue_active, 0); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ cmpb(queue_active, 0); + } + __ jcc(Assembler::equal, done); + // Can we store original value in the thread's buffer? __ movptr(tmp, queue_index); diff --git a/hotspot/src/cpu/x86/vm/frame_x86.cpp b/hotspot/src/cpu/x86/vm/frame_x86.cpp index 9cbc29af4c9..11f28bdb6ca 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp @@ -376,7 +376,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp fr._unextended_sp = unextended_sp; address original_pc = nm->get_original_pc(&fr); - assert(nm->insts_contains(original_pc), "original PC must be in CompiledMethod"); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); } #endif diff --git a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp index d7d8e47ea89..d0c72947e0f 100644 --- a/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp +++ b/hotspot/src/cpu/x86/vm/frame_x86.inline.hpp @@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address address original_pc = CompiledMethod::get_deopt_original_pc(this); if (original_pc != NULL) { _pc = original_pc; - assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod"); + assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { if (_cb->is_deoptimization_stub()) { diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 3d4dee751a5..b6d32631582 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -3499,12 +3499,12 @@ void MacroAssembler::movdqu(XMMRegister dst, XMMRegister src) { } } -void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) { +void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg) { if (reachable(src)) { movdqu(dst, as_Address(src)); } else { - lea(rscratch1, src); - movdqu(dst, Address(rscratch1, 0)); + lea(scratchReg, src); + movdqu(dst, Address(scratchReg, 0)); } } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 02fb401511e..a3e81e58dc5 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1085,7 +1085,7 @@ public: void movdqu(Address dst, XMMRegister src); void movdqu(XMMRegister dst, Address src); void movdqu(XMMRegister dst, XMMRegister src); - void movdqu(XMMRegister dst, AddressLiteral src); + void movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg = rscratch1); // AVX Unaligned forms void vmovdqu(Address dst, XMMRegister src); void vmovdqu(XMMRegister dst, Address src); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp index 37d93a48f21..10935345f70 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86_sha.cpp @@ -817,7 +817,7 @@ enum { movl(d, Address(CTX, 4*3)); movl(e, Address(CTX, 4*4)); movl(f, Address(CTX, 4*5)); - movl(g, Address(CTX, 4*6)); + // load g - r10 after it is used as scratch movl(h, Address(CTX, 4*7)); pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask; @@ -825,6 +825,8 @@ enum { vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip] vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip] + movl(g, Address(CTX, 4*6)); + movq(Address(rsp, _CTX), CTX); // store bind(loop0); @@ -977,7 +979,7 @@ bind(only_one_block); movl(d, Address(CTX, 4*3)); // 0xa54ff53a movl(e, Address(CTX, 4*4)); // 0x510e527f movl(f, Address(CTX, 4*5)); // 0x9b05688c - movl(g, Address(CTX, 4*6)); // 0x1f83d9ab + // load g - r10 after use as scratch movl(h, Address(CTX, 4*7)); // 0x5be0cd19 @@ -986,6 +988,8 @@ bind(only_one_block); vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip] vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip] + movl(g, Address(CTX, 4*6)); // 0x1f83d9ab + movq(Address(rsp, _CTX), CTX); jmpb(do_last_block); @@ -1154,9 +1158,8 @@ void MacroAssembler::sha512_AVX2_one_round_and_schedule( // Move to appropriate lanes for calculating w[16] and w[17] vperm2f128(xmm4, xmm0, xmm0, 0); //xmm4 = W[-16] + W[-7] + s0{ BABA } - address MASK_YMM_LO = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512(); //Move to appropriate lanes for calculating w[18] and w[19] - vpand(xmm0, xmm0, ExternalAddress(MASK_YMM_LO + 32), AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 } + vpand(xmm0, xmm0, xmm10, AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 } //Calculate w[16] and w[17] in both 128 bit lanes //Calculate sigma1 for w[16] and w[17] on both 128 bit lanes vperm2f128(xmm2, xmm7, xmm7, 17); //xmm2 = W[-2] {BABA} @@ -1250,6 +1253,7 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste const XMMRegister& XFER = xmm0; // YTMP0 const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9 + const XMMRegister& YMM_MASK_LO = xmm10; // ymm10 #ifdef _WIN64 const Register& INP = rcx; //1st arg const Register& CTX = rdx; //2nd arg @@ -1368,11 +1372,14 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste movq(d, Address(CTX, 8 * 3)); movq(e, Address(CTX, 8 * 4)); movq(f, Address(CTX, 8 * 5)); - movq(g, Address(CTX, 8 * 6)); + // load g - r10 after it is used as scratch movq(h, Address(CTX, 8 * 7)); pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask_sha512; vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); //PSHUFFLE_BYTE_FLIP_MASK wrt rip + vmovdqu(YMM_MASK_LO, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); + + movq(g, Address(CTX, 8 * 6)); bind(loop0); lea(TBL, ExternalAddress(K512_W)); diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index 1853cf9a42a..48be33ae526 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -3207,7 +3207,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) #else const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 - const Register len_reg = r10; // pick the first volatile windows register + const Register len_reg = r11; // pick the volatile windows register #endif const Register pos = rax; @@ -3404,7 +3404,7 @@ class StubGenerator: public StubCodeGenerator { const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16) #else const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64 - const Register len_reg = r10; // pick the first volatile windows register + const Register len_reg = r11; // pick the volatile windows register #endif const Register pos = rax; @@ -3930,7 +3930,7 @@ class StubGenerator: public StubCodeGenerator { __ push(rbx); // Save RBX __ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter - __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr())); + __ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()), pos); // pos as scratch __ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled __ movptr(pos, 0); @@ -3953,7 +3953,7 @@ class StubGenerator: public StubCodeGenerator { __ movl(Address(used_addr, 0), used); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} - __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr())); + __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); // rbx as scratch __ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); __ cmpl(rbx, 52); __ jcc(Assembler::equal, L_multiBlock_loopTop[1]); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java index 7be7a80192e..6cd7a4ad8b0 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -37,6 +37,7 @@ import jdk.tools.jaotc.binformat.Symbol.Binding; import jdk.tools.jaotc.binformat.Symbol.Kind; import jdk.tools.jaotc.binformat.elf.JELFRelocObject; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; /** * A format-agnostic container class that holds various components of a binary. @@ -257,9 +258,9 @@ public class BinaryContainer implements SymbolTable { * prefix {@code prefix}. It also initializes internal code container, symbol table and * relocation tables. */ - public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) { - this.codeSegmentSize = config.codeSegmentSize; - this.codeEntryAlignment = config.codeEntryAlignment; + public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) { + this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize; + this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment; // read only, code codeContainer = new CodeContainer(".text", this); @@ -289,30 +290,31 @@ public class BinaryContainer implements SymbolTable { addGlobalSymbols(); - recordConfiguration(config); + recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig); } - private void recordConfiguration(GraalHotSpotVMConfig config) { + private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig) { // @formatter:off - boolean[] booleanFlags = { config.cAssertions, // Debug VM - config.useCompressedOops, - config.useCompressedClassPointers, - config.compactFields, - config.useG1GC, - config.useCMSGC, - config.useTLAB, - config.useBiasedLocking, + boolean[] booleanFlags = { graalHotSpotVMConfig.cAssertions, // Debug VM + graalHotSpotVMConfig.useCompressedOops, + graalHotSpotVMConfig.useCompressedClassPointers, + graalHotSpotVMConfig.compactFields, + graalHotSpotVMConfig.useG1GC, + graalHotSpotVMConfig.useCMSGC, + graalHotSpotVMConfig.useTLAB, + graalHotSpotVMConfig.useBiasedLocking, TieredAOT.getValue(), - config.enableContended, - config.restrictContended, + graalHotSpotVMConfig.enableContended, + graalHotSpotVMConfig.restrictContended, + graphBuilderConfig.omitAssertions() }; - int[] intFlags = { config.narrowOopShift, - config.narrowKlassShift, - config.contendedPaddingWidth, - config.fieldsAllocationStyle, - config.objectAlignment, - config.codeSegmentSize, + int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift, + graalHotSpotVMConfig.getKlassEncoding().shift, + graalHotSpotVMConfig.contendedPaddingWidth, + graalHotSpotVMConfig.fieldsAllocationStyle, + 1 << graalHotSpotVMConfig.getOopEncoding().alignment, + graalHotSpotVMConfig.codeSegmentSize, }; // @formatter:on @@ -395,6 +397,10 @@ public class BinaryContainer implements SymbolTable { return "_aot_narrow_klass_base_address"; } + public String getNarrowOopBaseAddressSymbolName() { + return "_aot_narrow_oop_base_address"; + } + public String getLogOfHeapRegionGrainBytesSymbolName() { return "_aot_log_of_heap_region_grain_bytes"; } @@ -445,6 +451,7 @@ public class BinaryContainer implements SymbolTable { createGotSymbol(getHeapTopAddressSymbolName()); createGotSymbol(getHeapEndAddressSymbolName()); createGotSymbol(getNarrowKlassBaseAddressSymbolName()); + createGotSymbol(getNarrowOopBaseAddressSymbolName()); createGotSymbol(getPollingPageSymbolName()); createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName()); createGotSymbol(getInlineContiguousAllocationSupportedSymbolName()); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java index b5d081a51ca..3ba1067b959 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java @@ -77,10 +77,14 @@ public class AOTBackend { this.filters = filters; providers = backend.getProviders(); codeCache = providers.getCodeCache(); - graphBuilderSuite = initGraphBuilderSuite(backend); + graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions); highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL); } + public PhaseSuite getGraphBuilderSuite() { + return graphBuilderSuite; + } + private Suites getSuites() { // create suites every time, as we modify options for the compiler return backend.getSuites().getDefaultSuites(); @@ -146,14 +150,14 @@ public class AOTBackend { return backend.getRuntime().getVMConfig().cAssertions; } - private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend) { + private static PhaseSuite initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) { PhaseSuite graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy(); ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); // Use all default plugins. Plugins plugins = baseConfig.getPlugins(); - GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true); + GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions); iterator.next(); iterator.remove(); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java index cbf26294b0d..68fb146b8ce 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompiledClass.java @@ -293,12 +293,18 @@ public class AOTCompiledClass { // Record methods holder methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType); // Record inlinee classes - for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) { - methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); + ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods(); + if (inlinees != null) { + for (ResolvedJavaMethod m : inlinees) { + methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass()); + } } // Record classes of fields that were accessed - for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) { - methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); + ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields(); + if (fields != null) { + for (ResolvedJavaField f : fields) { + methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass()); + } } } } diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java new file mode 100644 index 00000000000..a0a01f7c1c9 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/LoadedClass.java @@ -0,0 +1,64 @@ +package jdk.tools.jaotc;/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +public class LoadedClass { + private final String name; + private final Class clz; + + public LoadedClass(String name, Class clz) { + this.name = name; + this.clz = clz; + } + + public String getName() { + return name; + } + + public Class getLoadedClass() { + return clz; + } + + @Override + public String toString() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof LoadedClass)) return false; + + LoadedClass that = (LoadedClass) o; + + if (name != null ? !name.equals(that.name) : that.name != null) return false; + return clz != null ? clz.equals(that.clz) : that.clz == null; + + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (clz != null ? clz.hashCode() : 0); + return result; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java index a1257b7a013..a98dc8d2d81 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,19 +43,31 @@ import java.nio.file.Paths; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import java.util.Set; import java.util.stream.Stream; import jdk.tools.jaotc.binformat.BinaryContainer; import jdk.tools.jaotc.binformat.ByteContainer; -import jdk.tools.jaotc.collect.ClassCollector; +import jdk.tools.jaotc.collect.*; +import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider; +import jdk.tools.jaotc.collect.directory.DirectorySourceProvider; +import jdk.tools.jaotc.collect.jar.JarSourceProvider; +import jdk.tools.jaotc.collect.module.ModuleSourceProvider; import jdk.tools.jaotc.utils.Timer; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotHostBackend; +import org.graalvm.compiler.java.GraphBuilderPhase; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.runtime.RuntimeProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -120,17 +132,7 @@ public class Main implements LogPrinter { abstract void process(Main task, String opt, String arg) throws BadArgs; } - static Option[] recognizedOptions = {new Option(" --module Module to compile", true, "--module") { - @Override - void process(Main task, String opt, String arg) { - task.options.module = arg; - } - }, new Option(" --module-path Specify where to find module to compile", true, "--module-path") { - @Override - void process(Main task, String opt, String arg) { - task.options.modulepath = arg; - } - }, new Option(" --output Output file name", true, "--output") { + static Option[] recognizedOptions = { new Option(" --output Output file name", true, "--output") { @Override void process(Main task, String opt, String arg) { String name = arg; @@ -139,22 +141,48 @@ public class Main implements LogPrinter { } task.options.outputName = name; } + }, new Option(" --class-name List of classes to compile", true, "--class-name", "--classname") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg)); + } + }, new Option(" --jar List of jar files to compile", true, "--jar") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg)); + } + }, new Option(" --module List of modules to compile", true, "--module") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg)); + } + }, new Option(" --directory List of directories where to search for files to compile", true, "--directory") { + @Override + void process(Main task, String opt, String arg) { + task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg)); + } + }, new Option(" --search-path List of directories where to search for specified files", true, "--search-path") { + @Override + void process(Main task, String opt, String arg) { + String[] elements = arg.split(":"); + task.options.searchPath.add(elements); + } }, new Option(" --compile-commands Name of file with compile commands", true, "--compile-commands") { @Override void process(Main task, String opt, String arg) { task.options.methodList = arg; } - }, new Option(" --compile-for-tiered Generated profiling code for tiered compilation", false, "--compile-for-tiered") { + }, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") { @Override void process(Main task, String opt, String arg) { TieredAOT.setValue(true); } - }, new Option(" --classpath Specify where to find user class files", true, "--classpath", "--class-path") { + }, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") { @Override void process(Main task, String opt, String arg) { - task.options.classpath = arg; + task.options.compileWithAssertions = true; } - }, new Option(" --threads Number of compilation threads to be used", true, "--threads") { + }, new Option(" --compile-threads Number of compilation threads to be used", true, "--compile-threads", "--threads") { @Override void process(Main task, String opt, String arg) { int threads = Integer.parseInt(arg); @@ -213,27 +241,27 @@ public class Main implements LogPrinter { }}; public static class Options { - public List files = new LinkedList<>(); - public String module = null; - public String modulepath = "modules"; + public List files = new LinkedList<>(); public String outputName = "unnamed"; public String methodList; - public String classpath = "."; + public List sources = new ArrayList<>(); + public SearchPath searchPath = new SearchPath(); /** * We don't see scaling beyond 16 threads. */ private static final int COMPILER_THREADS = 16; - int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); + public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors()); public boolean ignoreClassLoadingErrors; public boolean exitOnError; - boolean info; - boolean verbose; - boolean debug; - boolean help; - boolean version; + public boolean info; + public boolean verbose; + public boolean debug; + public boolean help; + public boolean version; + public boolean compileWithAssertions; } /* package */final Options options = new Options(); @@ -275,7 +303,9 @@ public class Main implements LogPrinter { printlnInfo("Compiling " + options.outputName + "..."); final long start = System.currentTimeMillis(); - run(); + if (!run()) { + return EXIT_ABNORMAL; + } final long end = System.currentTimeMillis(); printlnInfo("Total time: " + (end - start) + " ms"); @@ -318,17 +348,34 @@ public class Main implements LogPrinter { } @SuppressWarnings("try") - private void run() throws Exception { + private boolean run() throws Exception { openLog(); try { CompilationSpec compilationRestrictions = collectSpecifiedMethods(); - Set> classesToCompile; + Set> classesToCompile = new HashSet<>(); try (Timer t = new Timer(this, "")) { - ClassCollector collector = new ClassCollector(this.options, this); - classesToCompile = collector.collectClassesToCompile(); + FileSupport fileSupport = new FileSupport(); + ClassSearch lookup = new ClassSearch(); + lookup.addProvider(new ModuleSourceProvider()); + lookup.addProvider(new ClassNameSourceProvider(fileSupport)); + lookup.addProvider(new JarSourceProvider()); + lookup.addProvider(new DirectorySourceProvider(fileSupport)); + + List found = null; + try { + found = lookup.search(options.files, options.searchPath); + } catch (InternalError e) { + reportError(e); + return false; + } + + for (LoadedClass loadedClass : found) { + classesToCompile.add(loadedClass.getLoadedClass()); + } + printInfo(classesToCompile.size() + " classes found"); } @@ -356,6 +403,11 @@ public class Main implements LogPrinter { AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads); classes = compiler.compileClasses(classes); + GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig(); + PhaseSuite graphBuilderSuite = aotBackend.getGraphBuilderSuite(); + ListIterator> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class); + GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig(); + // Free memory! try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) { printMemoryUsage(); @@ -364,7 +416,7 @@ public class Main implements LogPrinter { System.gc(); } - BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION); + BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION); DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer); dataBuilder.prepareData(); @@ -446,6 +498,7 @@ public class Main implements LogPrinter { } finally { closeLog(); } + return true; } private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) { @@ -509,7 +562,7 @@ public class Main implements LogPrinter { break; } } else { - options.files.add(arg); + options.files.add(new SearchFor(arg)); } } } @@ -570,6 +623,12 @@ public class Main implements LogPrinter { log.flush(); } + private void reportError(Throwable e) { + log.println("Error: " + e.getMessage()); + e.printStackTrace(log); + log.flush(); + } + private void reportError(String key, Object... args) { printError(MessageFormat.format(key, args)); } @@ -580,17 +639,17 @@ public class Main implements LogPrinter { } private void showUsage() { - log.println("Usage: " + PROGNAME + " list..."); + log.println("Usage: " + PROGNAME + " list"); log.println("use --help for a list of possible options"); } private void showHelp() { - log.println("Usage: " + PROGNAME + " <--module name> | "); + log.println("Usage: " + PROGNAME + " list"); log.println(); - log.println(" list A list of class files, jar files or directories which"); - log.println(" contains class files."); + log.println(" list A : separated list of class names, modules, jar files"); + log.println(" or directories which contain class files."); log.println(); - log.println("where possible options include:"); + log.println("where options include:"); for (Option o : recognizedOptions) { String name = o.aliases[0].substring(1); // there must always be at least one name name = name.charAt(0) == '-' ? name.substring(1) : name; diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java index 4bbd4665434..eedeac3b720 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkId.java @@ -48,6 +48,7 @@ enum MarkId { HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"), HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"), NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"), + NARROW_OOP_BASE_ADDRESS("CodeInstaller::NARROW_OOP_BASE_ADDRESS"), CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"), LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"), INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED"); diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java index 1e1944bc274..7a833c13914 100644 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/MarkProcessor.java @@ -57,6 +57,7 @@ class MarkProcessor { case HEAP_TOP_ADDRESS: case HEAP_END_ADDRESS: case NARROW_KLASS_BASE_ADDRESS: + case NARROW_OOP_BASE_ADDRESS: case CRC_TABLE_ADDRESS: case LOG_OF_HEAP_REGION_GRAIN_BYTES: case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: @@ -78,6 +79,9 @@ class MarkProcessor { case NARROW_KLASS_BASE_ADDRESS: vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName(); break; + case NARROW_OOP_BASE_ADDRESS: + vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName(); + break; case CRC_TABLE_ADDRESS: vmSymbolName = binaryContainer.getCrcTableAddressSymbolName(); break; diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java deleted file mode 100644 index c46b3bfd062..00000000000 --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassCollector.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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.tools.jaotc.collect; - -import jdk.tools.jaotc.LogPrinter; -import jdk.tools.jaotc.Main; - -import java.io.File; -import java.io.IOException; -import java.net.*; -import java.nio.file.*; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.*; - -import static java.nio.file.FileVisitResult.CONTINUE; - -public class ClassCollector { - private final Main.Options options; - private final LogPrinter log; - - public ClassCollector(Main.Options options, LogPrinter log) { - this.options = options; - this.log = log; - } - - /** - * Collect all class names passed by the user. - * - * @return array list of classes - */ - public Set> collectClassesToCompile() { - Set> classes = new HashSet<>(); - List filesToScan = new LinkedList<>(options.files); - - if (options.module != null) { - classes.addAll(scanModule(filesToScan)); - } - - classes.addAll(scanFiles(filesToScan)); - return classes; - } - - private Set> scanModule(List filesToScan) { - String module = options.module; - // Search module in standard JDK installation. - Path dir = getModuleDirectory(options.modulepath, module); - - if (Files.isDirectory(dir)) { - return loadFromModuleDirectory(dir); - } else { - findFilesToScan(filesToScan, module); - return new HashSet<>(); - } - } - - private Set> loadFromModuleDirectory(Path dir) { - log.printInfo("Scanning module: " + dir + " ..."); - log.printlnVerbose(" "); // Break line - - FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString())); - Set> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder); - log.printlnInfo(" " + cls.size() + " classes loaded."); - return cls; - } - - private void findFilesToScan(List filesToScan, String module) { - // Try to search regular directory, .jar or .class files - Path path = Paths.get(options.modulepath, module); - - if (Files.isDirectory(path)) { - filesToScan.add("."); - options.classpath = path.toString(); - } else if (path.endsWith(".jar") || path.endsWith(".class")) { - filesToScan.add(path.toString()); - } else { - path = Paths.get(options.modulepath, module + ".jar"); - if (Files.exists(path)) { - filesToScan.add(path.toString()); - } else { - path = Paths.get(options.modulepath, module + ".class"); - if (Files.exists(path)) { - filesToScan.add(path.toString()); - } else { - throw new InternalError("Expecting a .class, .jar or directory: " + path); - } - } - } - } - - private boolean entryIsClassFile(String entry) { - return entry.endsWith(".class") && !entry.endsWith("module-info.class"); - } - - private Set> scanFiles(List filesToScan) { - Set> classes = new HashSet<>(); - for (String fileName : filesToScan) { - Set> loaded = scanFile(fileName); - log.printlnInfo(" " + loaded.size() + " classes loaded."); - classes.addAll(loaded); - } - return classes; - } - - interface ClassLoaderFactory { - ClassLoader create() throws IOException; - } - - private Set> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) { - ClassLoader loader = null; - try { - loader = factory.create(); - return loadClassFiles(root, finder, loader); - } catch (IOException e) { - throw new InternalError(e); - } finally { - if (loader instanceof AutoCloseable) { - try { - ((AutoCloseable) loader).close(); - } catch (Exception e) { - throw new InternalError(e); - } - } - } - } - - private Set> scanFile(String fileName) { - log.printInfo("Scanning: " + fileName + " ..."); - log.printlnVerbose(" "); // Break line - - if (fileName.endsWith(".jar")) { - return loadFromJarFile(fileName); - } else if (fileName.endsWith(".class")) { - Set> classes = new HashSet<>(); - loadFromClassFile(fileName, classes); - return classes; - } else { - return scanClassPath(fileName); - } - } - - private Set> loadFromJarFile(String fileName) { - FileSystem fs = makeFileSystem(fileName); - FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString())); - return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder); - } - - private void loadFromClassFile(String fileName, Set> classes) { - Class result; - File file = new File(options.classpath); - try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { - result = loadClassFile(loader, fileName); - } catch (IOException e) { - throw new InternalError(e); - } - Class c = result; - addClass(classes, fileName, c); - } - - private Set> scanClassPath(String fileName) { - Path classPath = Paths.get(options.classpath); - if (!Files.exists(classPath)) { - throw new InternalError("Path does not exist: " + classPath); - } - if (!Files.isDirectory(classPath)) { - throw new InternalError("Path must be a directory: " + classPath); - } - - // Combine class path and file name and see what it is. - Path combinedPath = Paths.get(options.classpath + File.separator + fileName); - if (combinedPath.endsWith(".class")) { - throw new InternalError("unimplemented"); - } else if (Files.isDirectory(combinedPath)) { - return scanDirectory(classPath, combinedPath); - } else { - throw new InternalError("Expecting a .class, .jar or directory: " + fileName); - } - } - - private FileSystem makeFileSystem(String fileName) { - try { - return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>()); - } catch (IOException e) { - throw new InternalError(e); - } - } - - private URI makeJarFileURI(String fileName) { - try { - return new URI("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/"); - } catch (URISyntaxException e) { - throw new InternalError(e); - } - } - - private PathMatcher combine(PathMatcher m1, PathMatcher m2) { - return path -> m1.matches(path) && m2.matches(path); - } - - private Set> scanDirectory(Path classPath, Path combinedPath) { - String dir = options.classpath; - - FileSystem fileSystem = FileSystems.getDefault(); - PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class"); - FileSystemFinder finder = new FileSystemFinder(combinedPath, - combine(matcher, pathname -> entryIsClassFile(pathname.toString()))); - - File file = new File(dir); - try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) { - return loadClassFiles(classPath, finder, loader); - } catch (IOException e) { - throw new InternalError(e); - } - } - - private Set> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) { - Set> classes = new HashSet<>(); - for (Path name : finder.done()) { - // Now relativize to the class path so we get the actual class names. - String entry = root.relativize(name).normalize().toString(); - Class c = loadClassFile(loader, entry); - addClass(classes, entry, c); - } - return classes; - } - - private void addClass(Set> classes, String name, Class c) { - if (c != null) { - classes.add(c); - log.printlnVerbose(" loaded " + name); - } - } - - private URL[] buildUrls(String fileName) throws MalformedURLException { - return new URL[]{ new URL("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/") }; - } - - private URL[] buildUrls(File file) throws MalformedURLException { - return new URL[] {file.toURI().toURL() }; - } - - private Path getModuleDirectory(String modulepath, String module) { - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - return fs.getPath(modulepath, module); - } - - /** - * Loads a class with the given file name from the specified {@link URLClassLoader}. - */ - private Class loadClassFile(final ClassLoader loader, final String fileName) { - int start = 0; - if (fileName.startsWith("/")) { - start = 1; - } - String className = fileName.substring(start, fileName.length() - ".class".length()); - className = className.replace('/', '.'); - try { - return loader.loadClass(className); - } catch (Throwable e) { - // If we are running in JCK mode we ignore all exceptions. - if (options.ignoreClassLoadingErrors) { - log.printError(className + ": " + e); - return null; - } - throw new InternalError(e); - } - } - - /** - * {@link FileVisitor} implementation to find class files recursively. - */ - private static class FileSystemFinder extends SimpleFileVisitor { - private final ArrayList fileNames = new ArrayList<>(); - private final PathMatcher filter; - - FileSystemFinder(Path combinedPath, PathMatcher filter) { - this.filter = filter; - try { - Files.walkFileTree(combinedPath, this); - } catch (IOException e) { - throw new InternalError(e); - } - } - - /** - * Compares the glob pattern against the file name. - */ - void find(Path file) { - Path name = file.getFileName(); - if (name != null && filter.matches(name)) { - fileNames.add(file); - } - } - - List done() { - return fileNames; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - find(file); - return CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - find(dir); - return CONTINUE; - } - - } -} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java new file mode 100644 index 00000000000..3fd63b2c0b8 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSearch.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect; + +import jdk.tools.jaotc.LoadedClass; + +import java.util.ArrayList; +import java.util.List; + +public class ClassSearch { + private List providers = new ArrayList<>(); + + public void addProvider(SourceProvider provider) { + providers.add(provider); + } + + public List search(List search, SearchPath searchPath) { + List loaded = new ArrayList<>(); + + List sources = new ArrayList<>(); + + for (SearchFor entry : search) { + sources.add(findSource(entry, searchPath)); + } + + for (ClassSource source : sources) { + source.eachClass((name, loader) -> loaded.add(loadClass(name, loader))); + } + + return loaded; + } + + private LoadedClass loadClass(String name, ClassLoader loader) { + try { + Class clzz = loader.loadClass(name); + return new LoadedClass(name, clzz); + } catch (ClassNotFoundException e) { + throw new InternalError("Failed to load with: " + loader, e); + } + } + + private ClassSource findSource(SearchFor searchFor, SearchPath searchPath) { + ClassSource found = null; + + for (SourceProvider provider : providers) { + if (!searchFor.isUnknown() && !provider.supports(searchFor.getType())) { + continue; + } + + ClassSource source = provider.findSource(searchFor.getName(), searchPath); + if (source != null) { + if (found != null) { + throw new InternalError("Multiple possible sources: " + source + " and: " + found); + } + found = source; + } + } + + if (found == null) { + throw new InternalError("Failed to find: " + searchFor.toString()); + } + return found; + } + + public static List makeList(String type, String argument) { + List list = new ArrayList<>(); + String[] elements = argument.split(":"); + for (String element : elements) { + list.add(new SearchFor(element, type)); + } + return list; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java new file mode 100644 index 00000000000..8d9b8439760 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/ClassSource.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public interface ClassSource { + static boolean pathIsClassFile(Path entry) { + String fileName = entry.getFileName().toString(); + return fileName.endsWith(".class") && !fileName.endsWith("module-info.class"); + } + + static String makeClassName(Path path) { + String fileName = path.toString(); + + if (!fileName.endsWith(".class")) { + throw new IllegalArgumentException("File doesn't end with .class: '" + fileName + "'"); + } + + int start = 0; + if (fileName.startsWith("/")) { + start = 1; + } + + String className = fileName.substring(start, fileName.length() - ".class".length()); + className = className.replace('/', '.'); + return className; + } + + void eachClass(BiConsumer consumer); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java new file mode 100644 index 00000000000..0761c0ae8e1 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSupport.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect; + +import java.io.IOException; +import java.net.*; +import java.nio.file.*; +import java.util.HashMap; + +public class FileSupport { + public boolean exists(Path path) { + return Files.exists(path); + } + + public boolean isDirectory(Path path) { + return Files.isDirectory(path); + } + + private FileSystem makeJarFileSystem(Path path) { + try { + return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>()); + } catch (IOException e) { + throw new InternalError(e); + } + } + + private URI makeJarFileURI(Path path) { + try { + return new URI("jar:file:" + path.toAbsolutePath() + "!/"); + } catch (URISyntaxException e) { + throw new InternalError(e); + } + } + + public ClassLoader createClassLoader(Path path, ClassLoader parent) { + try { + return URLClassLoader.newInstance(buildUrls(path), parent); + } catch (MalformedURLException e) { + throw new InternalError(e); + } + } + + public ClassLoader createClassLoader(Path path) throws MalformedURLException { + return URLClassLoader.newInstance(buildUrls(path)); + } + + private URL[] buildUrls(Path path) throws MalformedURLException { + return new URL[] { path.toUri().toURL() }; + } + + public Path getJarFileSystemRoot(Path jarFile) { + FileSystem fileSystem = makeJarFileSystem(jarFile); + return fileSystem.getPath("/"); + } + + public boolean isAbsolute(Path entry) { + return entry.isAbsolute(); + } + + public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException { + DirectoryStream paths = fileSystem.provider().newDirectoryStream(root,null); + for (Path entry : paths) { + Path relative = root.relativize(entry); + if (relative.equals(path)) { + return entry; + } + } + return null; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java new file mode 100644 index 00000000000..7838104b89c --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/FileSystemFinder.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect; + +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Iterator; + +import static java.nio.file.FileVisitResult.CONTINUE; + +/** + * {@link FileVisitor} implementation to find class files recursively. + */ +public class FileSystemFinder extends SimpleFileVisitor implements Iterable { + private final ArrayList fileNames = new ArrayList<>(); + private final PathMatcher filter; + + public FileSystemFinder(Path combinedPath, PathMatcher filter) { + this.filter = filter; + try { + Files.walkFileTree(combinedPath, this); + } catch (IOException e) { + throw new InternalError(e); + } + } + + /** + * Compares the glob pattern against the file name. + */ + private void find(Path file) { + Path name = file.getFileName(); + if (name != null && filter.matches(name)) { + fileNames.add(file); + } + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { + find(file); + return CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + find(dir); + return CONTINUE; + } + + + @Override + public Iterator iterator() { + return fileNames.iterator(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java new file mode 100644 index 00000000000..49e0cdd9945 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchFor.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect; + +public class SearchFor { + private final String name; + private final String type; + + public SearchFor(String name) { + this(name, "unknown"); + } + + public SearchFor(String name, String type) { + this.name = name; + this.type = type; + } + + public boolean isUnknown() { + return "unknown".equals(type); + } + + public String getType() { + return this.type; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return type + ":" + name; + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java new file mode 100644 index 00000000000..19442069f16 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SearchPath.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect; + +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class SearchPath { + private final List searchPaths = new ArrayList<>(); + private final FileSupport fileSupport; + + public SearchPath() { + this(new FileSupport()); + } + + public SearchPath(FileSupport fileSupport) { + this.fileSupport = fileSupport; + } + + public Path find(FileSystem fileSystem, Path entry, String... defaults) { + if (isAbsolute(entry)) { + if (exists(entry)) { + return entry; + } + return null; + } + + if (exists(entry)) { + return entry; + } + + for (String searchPath : defaults) { + Path newPath = fileSystem.getPath(searchPath, entry.toString()); + if (exists(newPath)) { + return newPath; + } + } + + for (Path searchPath : searchPaths) { + Path newPath = fileSystem.getPath(searchPath.toString(), entry.toString()); + if (exists(newPath)) { + return newPath; + } + } + + return null; + } + + private boolean isAbsolute(Path entry) { + return fileSupport.isAbsolute(entry); + } + + private boolean exists(Path entry) { + return fileSupport.exists(entry); + } + + public void add(String... paths) { + for (String name : paths) { + Path path = Paths.get(name); + searchPaths.add(path); + } + } +} + diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java new file mode 100644 index 00000000000..5effa83c8fa --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/SourceProvider.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect; + +public interface SourceProvider { + ClassSource findSource(String name, SearchPath searchPath); + + boolean supports(String type); +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java new file mode 100644 index 00000000000..22227d03882 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSource.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.classname; + +import jdk.tools.jaotc.collect.ClassSource; + +import java.util.function.BiConsumer; + +public class ClassNameSource implements ClassSource { + private final String name; + private final ClassLoader classLoader; + + public ClassNameSource(String name, ClassLoader classLoader) { + this.name = name; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + consumer.accept(name, classLoader); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java new file mode 100644 index 00000000000..b5bc2804ed4 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/classname/ClassNameSourceProvider.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.classname; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ClassNameSourceProvider implements SourceProvider { + public final static String TYPE = "classname"; + private final ClassLoader classLoader; + + public ClassNameSourceProvider(FileSupport fileSupport) { + String classPath = System.getProperty("java.class.path"); + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + if (classPath != null && !classPath.isEmpty()) { + classLoader = systemClassLoader; + } else { + Path path = Paths.get(".").toAbsolutePath(); + classLoader = fileSupport.createClassLoader(path, systemClassLoader); + } + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + try { + classLoader.loadClass(name); + return new ClassNameSource(name, classLoader); + } catch (ClassNotFoundException e) { + return null; + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java new file mode 100644 index 00000000000..8e5cdb5bc47 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySource.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.directory; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class DirectorySource implements ClassSource { + private final Path directoryPath; + private final ClassLoader classLoader; + + public DirectorySource(Path directoryPath, ClassLoader classLoader) { + this.directoryPath = directoryPath; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(directoryPath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(directoryPath.relativize(path).normalize()), classLoader); + } + } + + @Override + public String toString() { + return "directory:" + directoryPath.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java new file mode 100644 index 00000000000..013e3858830 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/directory/DirectorySourceProvider.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.directory; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.net.MalformedURLException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; + +public class DirectorySourceProvider implements SourceProvider { + private final FileSupport fileSupport; + private final FileSystem fileSystem; + public final static String TYPE = "directory"; + + public DirectorySourceProvider(FileSupport fileSupport) { + this.fileSupport = fileSupport; + fileSystem = FileSystems.getDefault(); + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path directoryPath = fileSystem.getPath(name); + + if (!fileSupport.exists(directoryPath)) { + return null; + } + if (!fileSupport.isDirectory(directoryPath)) { + return null; + } + + try { + ClassLoader classLoader = fileSupport.createClassLoader(directoryPath); + return new DirectorySource(directoryPath, classLoader); + } catch (MalformedURLException e) { + return null; + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java new file mode 100644 index 00000000000..af7330a53b8 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarFileSource.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.jar; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class JarFileSource implements ClassSource { + private final Path jarFile; + private final Path jarRootPath; + private final ClassLoader classLoader; + + + public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) { + this.jarFile = jarFile; + this.jarRootPath = jarRootPath; + this.classLoader = classLoader; + } + + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(jarRootPath.relativize(path).normalize()), classLoader); + } + } + + @Override + public String toString() { + return "jar:" + jarFile.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java new file mode 100644 index 00000000000..f876c740b74 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/jar/JarSourceProvider.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.jar; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.net.MalformedURLException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; + +public class JarSourceProvider implements SourceProvider { + private final FileSystem fileSystem; + private final FileSupport fileSupport; + public final static String TYPE = "jar"; + + public JarSourceProvider() { + this(new FileSupport()); + } + + public JarSourceProvider(FileSupport fileSupport) { + this.fileSupport = fileSupport; + fileSystem = FileSystems.getDefault(); + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path fileName = fileSystem.getPath(name); + Path jarFile = searchPath.find(fileSystem, fileName); + + if (!validPath(jarFile)) { + return null; + } + + return createSource(jarFile); + } + + private ClassSource createSource(Path jarFile) { + try { + Path jarRootPath = fileSupport.getJarFileSystemRoot(jarFile); + if (jarRootPath == null) { + return null; + } + ClassLoader classLoader = fileSupport.createClassLoader(jarFile); + return new JarFileSource(jarFile, jarRootPath, classLoader); + } catch (ProviderNotFoundException | MalformedURLException e) { + } + return null; + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } + + private boolean validPath(Path jarFile) { + return jarFile != null && !fileSupport.isDirectory(jarFile); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java new file mode 100644 index 00000000000..bac5624ab6a --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSource.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.module; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSystemFinder; + +import java.nio.file.Path; +import java.util.function.BiConsumer; + +public class ModuleSource implements ClassSource { + private final Path modulePath; + private final ClassLoader classLoader; + + public ModuleSource(Path modulePath, ClassLoader classLoader) { + this.modulePath = modulePath; + this.classLoader = classLoader; + } + + @Override + public void eachClass(BiConsumer consumer) { + FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile); + + for (Path path : finder) { + consumer.accept(ClassSource.makeClassName(modulePath.relativize(path).normalize()), classLoader); + } + } + + public Path getModulePath() { + return modulePath; + } + + @Override + public String toString() { + return "module:" + modulePath.toString(); + } +} diff --git a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java new file mode 100644 index 00000000000..cd1a464b6f9 --- /dev/null +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/collect/module/ModuleSourceProvider.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 jdk.tools.jaotc.collect.module; + +import jdk.tools.jaotc.collect.ClassSource; +import jdk.tools.jaotc.collect.FileSupport; +import jdk.tools.jaotc.collect.SearchPath; +import jdk.tools.jaotc.collect.SourceProvider; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; + +public class ModuleSourceProvider implements SourceProvider { + private final FileSystem fileSystem; + private final ClassLoader classLoader; + private final FileSupport fileSupport; + public final static String TYPE = "module"; + + public ModuleSourceProvider() { + this(FileSystems.getFileSystem(URI.create("jrt:/")), ClassLoader.getSystemClassLoader(), new FileSupport()); + } + + public ModuleSourceProvider(FileSystem fileSystem, ClassLoader classLoader, FileSupport fileSupport) { + this.fileSystem = fileSystem; + this.classLoader = classLoader; + this.fileSupport = fileSupport; + } + + @Override + public ClassSource findSource(String name, SearchPath searchPath) { + Path path = fileSystem.getPath(name); + Path dir = fileSystem.getPath("modules"); + + if (dir == null || !fileSupport.isDirectory(dir)) { + return null; + } + + Path found = findModuleDirectory(dir, path); + + if (found == null) { + return null; + } + + return new ModuleSource(found, classLoader); + } + + private Path findModuleDirectory(Path root, Path path) { + try { + return fileSupport.getSubDirectory(fileSystem, root, path); + } catch (IOException e) { + throw new InternalError(e); + } + } + + @Override + public boolean supports(String type) { + return TYPE.equals(type); + } +} diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java index f92f91b7c78..e0b5acb426f 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java @@ -100,15 +100,19 @@ final class CompilerToVM { native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method); /** - * Determines if {@code method} can be inlined. A method may not be inlinable for a number of - * reasons such as: - *
    - *
  • a CompileOracle directive may prevent inlining or compilation of methods
  • - *
  • the method may have a bytecode breakpoint set
  • - *
  • the method may have other bytecode features that require special handling by the VM
  • - *
+ * Determines whether {@code method} is currently compilable by the JVMCI compiler being used by + * the VM. This can return false if JVMCI compilation failed earlier for {@code method}, a + * breakpoint is currently set in {@code method} or {@code method} contains other bytecode + * features that require special handling by the VM. */ - native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method); + native boolean isCompilable(HotSpotResolvedJavaMethodImpl method); + + /** + * Determines if {@code method} is targeted by a VM directive (e.g., + * {@code -XX:CompileCommand=dontinline,}) or annotation (e.g., + * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined. + */ + native boolean hasNeverInlineDirective(HotSpotResolvedJavaMethodImpl method); /** * Determines if {@code method} should be inlined at any cost. This could be because: diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java index dc56435038a..af75f81a2ff 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java @@ -49,13 +49,6 @@ public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod { */ boolean isForceInline(); - /** - * Returns true if this method has a {@code DontInline} annotation. - * - * @return true if DontInline annotation present, false otherwise - */ - boolean isDontInline(); - /** * Returns true if this method has a {@code ReservedStackAccess} annotation. * diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java index ad4c67d0275..393b740a71e 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java @@ -298,15 +298,6 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp return (getFlags() & config().methodFlagsForceInline) != 0; } - /** - * Returns true if this method has a {@code DontInline} annotation. - * - * @return true if DontInline annotation present, false otherwise - */ - public boolean isDontInline() { - return (getFlags() & config().methodFlagsDontInline) != 0; - } - /** * Returns true if this method has a {@code ReservedStackAccess} annotation. * @@ -582,10 +573,15 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp @Override public boolean canBeInlined() { - if (isDontInline()) { + if (hasNeverInlineDirective()) { return false; } - return compilerToVM().canInlineMethod(this); + return compilerToVM().isCompilable(this); + } + + @Override + public boolean hasNeverInlineDirective() { + return compilerToVM().hasNeverInlineDirective(this); } @Override diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java index 6d13d911398..dee43ffbc6a 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -346,6 +346,13 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP */ boolean canBeInlined(); + /** + * Determines if this method is targeted by a VM directive (e.g., + * {@code -XX:CompileCommand=dontinline,}) or VM recognized annotation (e.g., + * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined. + */ + boolean hasNeverInlineDirective(); + /** * Returns {@code true} if the inlining of this method should be forced. */ diff --git a/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py index 402eae2dae5..dda989acedf 100644 --- a/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py +++ b/hotspot/src/jdk.vm.compiler/.mx.graal/suite.py @@ -638,6 +638,7 @@ suite = { "annotationProcessors" : [ "GRAAL_NODEINFO_PROCESSOR", "GRAAL_REPLACEMENTS_VERIFIER", + "GRAAL_OPTIONS_PROCESSOR", ], "workingSets" : "Graal,Graph", }, diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java index f5a3758f066..cd5e7fca7ae 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java @@ -116,6 +116,7 @@ public class Debug { public static final int INFO_LOG_LEVEL = 2; public static final int VERBOSE_LOG_LEVEL = 3; public static final int DETAILED_LOG_LEVEL = 4; + public static final int VERY_DETAILED_LOG_LEVEL = 5; public static boolean isDumpEnabled(int dumpLevel) { return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel); diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java index 4ccc1bbc9ef..7cb4b03b27e 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java @@ -267,10 +267,15 @@ public class AMD64HotSpotBackend extends HotSpotHostBackend { if (config.useCompressedClassPointers) { Register register = r10; - AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding()); - if (config.narrowKlassBase != 0) { - // The heap base register was destroyed above, so restore it - asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, providers.getRegisters().getHeapBaseRegister(), src, config); + if (GeneratePIC.getValue()) { + asm.movq(providers.getRegisters().getHeapBaseRegister(), asm.getPlaceholder(-1)); + crb.recordMark(config.MARKID_NARROW_OOP_BASE_ADDRESS); + } else { + if (config.narrowKlassBase != 0) { + // The heap base register was destroyed above, so restore it + asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase); + } } asm.cmpq(inlineCacheKlass, register); } else { diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java index f7a5f205c26..168282ebcbf 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java @@ -265,14 +265,21 @@ public class AMD64HotSpotMove { } } - public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) { + public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) { + CompressEncoding encoding = config.getKlassEncoding(); masm.movl(register, address); if (encoding.shift != 0) { assert encoding.alignment == encoding.shift : "Decode algorithm is wrong"; masm.shlq(register, encoding.alignment); } - if (encoding.base != 0) { - masm.movq(scratch, encoding.base); + if (GeneratePIC.getValue() || encoding.base != 0) { + if (GeneratePIC.getValue()) { + masm.movq(scratch, masm.getPlaceholder(-1)); + crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS); + } else { + assert encoding.base != 0; + masm.movq(scratch, encoding.base); + } masm.addq(register, scratch); } } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java new file mode 100644 index 00000000000..3a93d463936 --- /dev/null +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/AOTGraalHotSpotVMConfig.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 org.graalvm.compiler.hotspot; + +import jdk.vm.ci.hotspot.HotSpotVMConfigStore; + +public class AOTGraalHotSpotVMConfig extends GraalHotSpotVMConfig { + private final CompressEncoding aotOopEncoding; + private final CompressEncoding aotKlassEncoding; + + public AOTGraalHotSpotVMConfig(HotSpotVMConfigStore store) { + super(store); + // In AOT, force the shift to be always equal to alignment therefore avoiding zero-shift. + CompressEncoding vmOopEncoding = super.getOopEncoding(); + aotOopEncoding = new CompressEncoding(vmOopEncoding.base, vmOopEncoding.alignment, vmOopEncoding.alignment); + CompressEncoding vmKlassEncoding = super.getKlassEncoding(); + aotKlassEncoding = new CompressEncoding(vmKlassEncoding.base, vmKlassEncoding.alignment, vmKlassEncoding.alignment); + assert check(); + } + + @Override + public CompressEncoding getOopEncoding() { + return aotOopEncoding; + } + + @Override + public CompressEncoding getKlassEncoding() { + return aotKlassEncoding; + } +} diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index e7ce8f68cce..898d688747d 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -479,7 +479,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address"); public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*"); - public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class); public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class); public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class); public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class); @@ -773,13 +772,14 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess { public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17); public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18); public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19); - public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20); - public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21); - public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22); + public final int MARKID_NARROW_OOP_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_OOP_BASE_ADDRESS", Integer.class, 20); + public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 21); + public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 22); + public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 23); // Checkstyle: resume - private boolean check() { + protected boolean check() { for (Field f : getClass().getDeclaredFields()) { int modifiers = f.getModifiers(); if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java index 01401eafd4a..401169124f4 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.hotspot; +import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.debug.GraalDebugConfig.areScopedGlobalMetricsEnabled; import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary; import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump; @@ -99,7 +100,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory) { HotSpotVMConfigStore store = jvmciRuntime.getConfigStore(); - config = new GraalHotSpotVMConfig(store); + config = GeneratePIC.getValue() ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store); CompileTheWorldOptions.overrideWithNativeOptions(config); // Only set HotSpotPrintInlining if it still has its default value (false). diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java index 89729e7e3f4..10b2255a3dc 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.hotspot.meta; -import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode; @@ -112,11 +111,6 @@ public final class HotSpotNodePlugin implements NodePlugin, TypePlugin { return true; } } - if (GeneratePIC.getValue()) { - if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) { - return tryReadField(b, field, null); - } - } if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) { return true; } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index bba5c70cfe4..7ace642641e 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -1738,9 +1738,8 @@ public class BytecodeParser implements GraphBuilderContext { } else { // Intrinsic was not applied: remove intrinsic guard // and restore the original receiver node in the arguments array - for (Node node : graph.getNewNodes(intrinsicGuard.mark)) { - GraphUtil.killCFG(node); - } + intrinsicGuard.lastInstr.setNext(null); + GraphUtil.removeNewNodes(graph, intrinsicGuard.mark); lastInstr = intrinsicGuard.lastInstr; args[0] = intrinsicGuard.receiver; } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java index f26b3004799..f2f833d2a90 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java @@ -153,9 +153,7 @@ public class SimplifyingGraphDecoder extends GraphDecoder { } for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) { - if (!(node instanceof FixedNode) && node.hasNoUsages()) { - GraphUtil.killCFG(node); - } + GraphUtil.tryKillUnused(node); } } diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java index af89e2711de..61603208b96 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java @@ -506,7 +506,7 @@ public class StructuredGraph extends Graph implements JavaMethodContext { for (Node successor : snapshot) { if (successor != null && successor.isAlive()) { if (successor != survivingSuccessor) { - GraphUtil.killCFG(successor, tool); + GraphUtil.killCFG((FixedNode) successor, tool); } } } @@ -566,6 +566,9 @@ public class StructuredGraph extends Graph implements JavaMethodContext { reduceTrivialMerge(begin); } else { // convert to merge AbstractMergeNode merge = this.add(new MergeNode()); + for (EndNode end : begin.forwardEnds()) { + merge.addForwardEnd(end); + } this.replaceFixedWithFixed(begin, merge); } } @@ -576,7 +579,14 @@ public class StructuredGraph extends Graph implements JavaMethodContext { for (PhiNode phi : merge.phis().snapshot()) { assert phi.valueCount() == 1; ValueNode singleValue = phi.valueAt(0); - phi.replaceAtUsagesAndDelete(singleValue); + if (phi.hasUsages()) { + phi.replaceAtUsagesAndDelete(singleValue); + } else { + phi.safeDelete(); + if (singleValue != null) { + GraphUtil.tryKillUnused(singleValue); + } + } } // remove loop exits if (merge instanceof LoopBeginNode) { diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java index f942d8c2358..210c5f793da 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * 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,18 +22,30 @@ */ package org.graalvm.compiler.nodes.util; +import static org.graalvm.compiler.graph.Graph.Options.VerifyGraalGraphEdges; +import static org.graalvm.compiler.nodes.util.GraphUtil.Options.VerifyKillCFGUnusedNodes; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; +import java.util.Set; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.code.SourceStackTraceBailoutException; +import org.graalvm.compiler.core.common.CollectionsFactory; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeWorkList; +import org.graalvm.compiler.graph.Position; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.graph.spi.SimplifierTool; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.AbstractMergeNode; @@ -48,11 +60,15 @@ import org.graalvm.compiler.nodes.ProxyNode; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; import org.graalvm.compiler.nodes.spi.LimitedValueProxy; import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.ValueProxy; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.BytecodePosition; @@ -64,22 +80,78 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; public class GraphUtil { - public static void killCFG(Node node, SimplifierTool tool) { - NodeWorkList worklist = killCFG(node, tool, null); - if (worklist != null) { - for (Node successor : worklist) { - killCFG(successor, tool, worklist); + public static class Options { + @Option(help = "Verify that there are no new unused nodes when performing killCFG", type = OptionType.Debug)// + public static final OptionValue VerifyKillCFGUnusedNodes = new OptionValue<>(false); + } + + @SuppressWarnings("try") + public static void killCFG(FixedNode node, SimplifierTool tool) { + try (Debug.Scope scope = Debug.scope("KillCFG", node)) { + Set unusedNodes = null; + Set unsafeNodes = null; + Graph.NodeEventScope nodeEventScope = null; + if (VerifyGraalGraphEdges.getValue()) { + unsafeNodes = collectUnsafeNodes(node.graph()); + } + if (VerifyKillCFGUnusedNodes.getValue()) { + Set collectedUnusedNodes = unusedNodes = CollectionsFactory.newSet(); + nodeEventScope = node.graph().trackNodeEvents(new Graph.NodeEventListener() { + @Override + public void event(Graph.NodeEvent e, Node n) { + if (e == Graph.NodeEvent.ZERO_USAGES && isFloatingNode(n)) { + collectedUnusedNodes.add(n); + } + } + }); + } + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "Before killCFG %s", node); + NodeWorkList worklist = killCFG(node, tool, null); + if (worklist != null) { + for (Node n : worklist) { + killCFG(n, tool, worklist); + } + } + if (VerifyGraalGraphEdges.getValue()) { + Set newUnsafeNodes = collectUnsafeNodes(node.graph()); + newUnsafeNodes.removeAll(unsafeNodes); + assert newUnsafeNodes.isEmpty() : "New unsafe nodes: " + newUnsafeNodes; + } + if (VerifyKillCFGUnusedNodes.getValue()) { + nodeEventScope.close(); + unusedNodes.removeIf(n -> n.isDeleted()); + assert unusedNodes.isEmpty() : "New unused nodes: " + unusedNodes; + } + } catch (Throwable t) { + throw Debug.handle(t); + } + } + + /** + * Collects all node in the graph which have non-optional inputs that are null. + */ + private static Set collectUnsafeNodes(Graph graph) { + Set unsafeNodes = CollectionsFactory.newSet(); + for (Node n : graph.getNodes()) { + for (Position pos : n.inputPositions()) { + Node input = pos.get(n); + if (input == null) { + if (!pos.isInputOptional()) { + unsafeNodes.add(n); + } + } } } + return unsafeNodes; } private static NodeWorkList killCFG(Node node, SimplifierTool tool, NodeWorkList worklist) { NodeWorkList newWorklist = worklist; - // DebugScope.forceDump(node.graph(), "kill CFG %s", node); if (node instanceof FixedNode) { newWorklist = killCFGLinear((FixedNode) node, newWorklist, tool); } else { - propagateKill(node); + newWorklist = propagateKill(node, newWorklist); + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "killCFG (Floating) %s", node); } return newWorklist; } @@ -93,19 +165,20 @@ public class GraphUtil { if (current instanceof AbstractEndNode) { // We reached a control flow end. AbstractEndNode end = (AbstractEndNode) current; - killEnd(end, tool); + newWorklist = killEnd(end, newWorklist, tool); } else if (current instanceof FixedWithNextNode) { - next = ((FixedWithNextNode) current).next(); + // Node guaranteed to have a single successor + FixedWithNextNode fixedWithNext = (FixedWithNextNode) current; + assert fixedWithNext.successors().count() == 1 || fixedWithNext.successors().count() == 0; + assert fixedWithNext.successors().first() == fixedWithNext.next(); + next = fixedWithNext.next(); } else { - // Normal control flow node. /* * We do not take a successor snapshot because this iterator supports concurrent * modifications as long as they do not change the size of the successor list. Not * taking a snapshot allows us to see modifications to other branches that may * happen while processing one branch. */ - // assert node.successors().count() > 1 || node.successors().count() == 0 : - // node.getClass(); Iterator successors = current.successors().iterator(); if (successors.hasNext()) { Node first = successors.next(); @@ -126,100 +199,158 @@ public class GraphUtil { } } current.replaceAtPredecessor(null); - propagateKill(current); + newWorklist = propagateKill(current, newWorklist); + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, current.graph(), "killCFGLinear %s", current); current = next; } + Debug.dump(Debug.DETAILED_LOG_LEVEL, in.graph(), "killCFGLinear %s", in); return newWorklist; } - public static void killCFG(Node node) { + public static void killCFG(FixedNode node) { killCFG(node, null); } - private static void killEnd(AbstractEndNode end, SimplifierTool tool) { + /** + * Node type used temporarily while deleting loops. + * + * It is used as replacement for the loop {@link PhiNode PhiNodes} in order to break data-flow + * cycles before deleting the loop. The control-flow of the whole loop is killed before killing + * the poison node if they are still alive. + */ + @NodeInfo(allowedUsageTypes = InputType.Unchecked) + private static final class PoisonNode extends FloatingNode { + public static final NodeClass TYPE = NodeClass.create(PoisonNode.class); + + protected PoisonNode() { + super(TYPE, StampFactory.forVoid()); + } + } + + private static NodeWorkList killEnd(AbstractEndNode end, NodeWorkList worklist, SimplifierTool tool) { + NodeWorkList newWorklist = worklist; AbstractMergeNode merge = end.merge(); if (merge != null) { merge.removeEnd(end); StructuredGraph graph = end.graph(); if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { // dead loop - for (PhiNode phi : merge.phis().snapshot()) { - propagateKill(phi); - } LoopBeginNode begin = (LoopBeginNode) merge; // disconnect and delete loop ends & loop exits for (LoopEndNode loopend : begin.loopEnds().snapshot()) { loopend.predecessor().replaceFirstSuccessor(loopend, null); loopend.safeDelete(); } - begin.removeExits(); - FixedNode loopBody = begin.next(); - if (loopBody != null) { // for small infinite loops, the body may be killed while - // killing the loop ends - killCFG(loopBody); + // clean unused proxies to avoid creating new unused nodes + for (LoopExitNode exit : begin.loopExits()) { + for (ProxyNode vpn : exit.proxies().snapshot()) { + tryKillUnused(vpn); + } } + begin.removeExits(); + PoisonNode poison = null; + if (merge.phis().isNotEmpty()) { + poison = graph.unique(new PoisonNode()); + for (PhiNode phi : merge.phis()) { + phi.replaceAtUsages(poison); + } + for (PhiNode phi : merge.phis().snapshot()) { + killWithUnusedFloatingInputs(phi); + } + } + FixedNode loopBody = begin.next(); + Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, end.graph(), "killEnd (Loop) %s after initial loop cleanup", end); + if (loopBody != null) { + // for small infinite loops, the body may already be killed while killing the + // LoopEnds + newWorklist = killCFG(loopBody, tool, worklist); + } + FrameState frameState = begin.stateAfter(); begin.safeDelete(); + if (frameState != null) { + tryKillUnused(frameState); + } + if (poison != null && poison.isAlive()) { + if (newWorklist == null) { + newWorklist = graph.createNodeWorkList(); + } + // drain the worklist to finish the loop before adding the poison + for (Node n : newWorklist) { + killCFG(n, tool, newWorklist); + } + if (poison.isAlive()) { + newWorklist.add(poison); + } + } } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore if (tool != null) { - merge.phis().forEach(phi -> tool.addToWorkList(phi.usages())); + for (PhiNode phi : merge.phis()) { + tool.addToWorkList(phi.usages()); + } } graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore if (tool != null) { - merge.phis().forEach(phi -> tool.addToWorkList(phi.usages())); + for (PhiNode phi : merge.phis()) { + tool.addToWorkList(phi.usages()); + } } graph.reduceTrivialMerge(merge); } } + return newWorklist; } public static boolean isFloatingNode(Node n) { return !(n instanceof FixedNode); } - private static void propagateKill(Node node) { + private static NodeWorkList propagateKill(Node node, NodeWorkList workList) { + NodeWorkList newWorkList = workList; if (node != null && node.isAlive()) { - node.markDeleted(); - - for (Node in : node.inputs()) { - if (in.isAlive()) { - in.removeUsage(node); - if (in.hasNoUsages() && !(in instanceof FixedNode)) { - killWithUnusedFloatingInputs(in); - } - } - } - - ArrayList usageToKill = null; - for (Node usage : node.usages()) { - if (usage.isAlive() && !(usage instanceof FixedNode)) { - if (usageToKill == null) { - usageToKill = new ArrayList<>(); - } - usageToKill.add(usage); - } - } - if (usageToKill != null) { - for (Node usage : usageToKill) { - if (usage.isAlive()) { - if (usage instanceof PhiNode) { - PhiNode phiNode = (PhiNode) usage; - usage.replaceFirstInput(node, null); - if (phiNode.merge() == null || !phiNode.hasValidInput()) { - propagateKill(usage); - } + for (Node usage : node.usages().snapshot()) { + assert usage.isAlive(); + if (isFloatingNode(usage)) { + boolean addUsage = false; + if (usage instanceof PhiNode) { + PhiNode phi = (PhiNode) usage; + assert phi.merge() != null; + if (phi.merge() == node) { + // we reach the phi directly through he merge, queue it. + addUsage = true; } else { - propagateKill(usage); + // we reach it though a value + assert phi.values().contains(node); + // let that be handled when we reach the corresponding End node } + } else { + addUsage = true; + } + if (addUsage) { + if (newWorkList == null) { + newWorkList = node.graph().createNodeWorkList(); + } + newWorkList.add(usage); } } + usage.replaceFirstInput(node, null); } + killWithUnusedFloatingInputs(node); } + return newWorkList; + } + + private static boolean checkKill(Node node) { + node.assertTrue(node.isAlive(), "must be alive"); + node.assertTrue(node.hasNoUsages(), "cannot kill node %s because of usages: %s", node, node.usages()); + node.assertTrue(node.predecessor() == null, "cannot kill node %s because of predecessor: %s", node, node.predecessor()); + return true; } public static void killWithUnusedFloatingInputs(Node node) { + assert checkKill(node); node.markDeleted(); outer: for (Node in : node.inputs()) { if (in.isAlive()) { @@ -227,7 +358,7 @@ public class GraphUtil { if (in.hasNoUsages()) { node.maybeNotifyZeroUsages(in); } - if (!(in instanceof FixedNode)) { + if (isFloatingNode(in)) { if (in.hasNoUsages()) { killWithUnusedFloatingInputs(in); } else if (in instanceof PhiNode) { @@ -244,6 +375,35 @@ public class GraphUtil { } } + /** + * Removes all nodes created after the {@code mark}, assuming no "old" nodes point to "new" + * nodes. + */ + public static void removeNewNodes(Graph graph, Graph.Mark mark) { + assert checkNoOldToNewEdges(graph, mark); + for (Node n : graph.getNewNodes(mark)) { + n.markDeleted(); + for (Node in : n.inputs()) { + in.removeUsage(n); + } + } + } + + private static boolean checkNoOldToNewEdges(Graph graph, Graph.Mark mark) { + for (Node old : graph.getNodes()) { + if (graph.isNew(mark, old)) { + break; + } + for (Node n : old.successors()) { + assert !graph.isNew(mark, n) : old + " -> " + n; + } + for (Node n : old.inputs()) { + assert !graph.isNew(mark, n) : old + " -> " + n; + } + } + return true; + } + public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) { if (fixed instanceof StateSplit) { FrameState stateAfter = ((StateSplit) fixed).stateAfter(); @@ -688,8 +848,9 @@ public class GraphUtil { @Override public void deleteBranch(Node branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch, this); + FixedNode fixedBranch = (FixedNode) branch; + fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); + GraphUtil.killCFG(fixedBranch, this); } @Override diff --git a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java index 35c0a41a7fb..d57d0d45c7a 100644 --- a/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java +++ b/hotspot/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java @@ -444,8 +444,9 @@ public class CanonicalizerPhase extends BasePhase { @Override public void deleteBranch(Node branch) { - branch.predecessor().replaceFirstSuccessor(branch, null); - GraphUtil.killCFG(branch, this); + FixedNode fixedBranch = (FixedNode) branch; + fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); + GraphUtil.killCFG(fixedBranch, this); } @Override diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index e900ce0af77..014d306e37f 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -632,7 +632,6 @@ void os::Aix::signal_sets_init() { sigaddset(&unblocked_sigs, SIGBUS); sigaddset(&unblocked_sigs, SIGFPE); sigaddset(&unblocked_sigs, SIGTRAP); - sigaddset(&unblocked_sigs, SIGDANGER); sigaddset(&unblocked_sigs, SR_signum); if (!ReduceSignalUsage) { @@ -1553,6 +1552,8 @@ void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) { print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen); print_signal_handler(st, BREAK_SIGNAL, buf, buflen); print_signal_handler(st, SIGTRAP, buf, buflen); + // We also want to know if someone else adds a SIGDANGER handler because + // that will interfere with OOM killling. print_signal_handler(st, SIGDANGER, buf, buflen); } @@ -3156,7 +3157,6 @@ void os::Aix::install_signal_handlers() { set_signal_handler(SIGFPE, true); set_signal_handler(SIGTRAP, true); set_signal_handler(SIGXFSZ, true); - set_signal_handler(SIGDANGER, true); if (libjsig_is_loaded) { // Tell libjsig jvm finishes setting signal handlers. @@ -3273,7 +3273,6 @@ void os::run_periodic_checks() { if (UseSIGTRAP) { DO_SIGNAL_CHECK(SIGTRAP); } - DO_SIGNAL_CHECK(SIGDANGER); // ReduceSignalUsage allows the user to override these handlers // see comments at the very top and jvm_solaris.h diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 5142cd37a25..23ad8e209cb 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -778,6 +778,11 @@ void os::set_native_thread_name(const char *name) { // is already attached to a debugger; debugger must observe // the exception below to show the correct name. + // If there is no debugger attached skip raising the exception + if (!IsDebuggerPresent()) { + return; + } + const DWORD MS_VC_EXCEPTION = 0x406D1388; struct { DWORD dwType; // must be 0x1000 diff --git a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp index 9bbb9387c54..721d99668b4 100644 --- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp +++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2016 SAP SE. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -258,13 +258,6 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec } } - // Handle SIGDANGER right away. AIX would raise SIGDANGER whenever available swap - // space falls below 30%. This is only a chance for the process to gracefully abort. - // We can't hope to proceed after SIGDANGER since SIGKILL tailgates. - if (sig == SIGDANGER) { - goto report_and_die; - } - if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) { goto run_chained_handler; } diff --git a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp index 24c124a4e8d..7767cecf0e4 100644 --- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp +++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp @@ -87,6 +87,7 @@ #define SPELL_REG_FP "rbp" #else #define REG_FP 29 +#define REG_LR 30 #define SPELL_REG_SP "sp" #define SPELL_REG_FP "x29" @@ -182,6 +183,46 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, fp, epc.pc()); } +bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Linux::ucontext_get_pc(uc); + if (Interpreter::contains(pc)) { + // interpreter performs stack banging after the fixed frame header has + // been generated while the compilers perform it before. To maintain + // semantic consistency between interpreted and compiled frames, the + // method returns the Java sender of the current frame. + *fr = os::fetch_frame_from_context(uc); + if (!fr->is_first_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } else { + // more complex code with compiled code + assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); + CodeBlob* cb = CodeCache::find_blob(pc); + if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { + // Not sure where the pc points to, fallback to default + // stack overflow handling + return false; + } else { + // In compiled code, the stack banging is performed before LR + // has been saved in the frame. LR is live, and SP and FP + // belong to the caller. + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + address pc = (address)(uc->uc_mcontext.regs[REG_LR] + - NativeInstruction::instruction_size); + *fr = frame(sp, fp, pc); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + assert(!fr->is_first_frame(), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + // By default, gcc always saves frame pointer rfp on this stack. This // may get turned off by -fomit-frame-pointer. frame os::get_sender_for_C_frame(frame* fr) { @@ -313,6 +354,24 @@ JVM_handle_linux_signal(int sig, if (thread->in_stack_yellow_reserved_zone(addr)) { thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) { + assert(fr.is_java_frame(), "Must be a Java frame"); + frame activation = + SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); + if (activation.sp() != NULL) { + thread->disable_stack_reserved_zone(); + if (activation.is_interpreted_frame()) { + thread->set_reserved_stack_activation((address)( + activation.fp() + frame::interpreter_frame_initial_sp_offset)); + } else { + thread->set_reserved_stack_activation((address)activation.unextended_sp()); + } + return 1; + } + } + } // Throw a stack overflow exception. Guard pages will be reenabled // while unwinding the stack. stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); diff --git a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp index 684853cfd34..e9120a8b696 100644 --- a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp +++ b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp @@ -144,6 +144,42 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, epc.pc()); } +bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { + address pc = (address) os::Linux::ucontext_get_pc(uc); + if (Interpreter::contains(pc)) { + // Interpreter performs stack banging after the fixed frame header has + // been generated while the compilers perform it before. To maintain + // semantic consistency between interpreted and compiled frames, the + // method returns the Java sender of the current frame. + *fr = os::fetch_frame_from_context(uc); + if (!fr->is_first_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + *fr = fr->java_sender(); + } + } else { + // More complex code with compiled code. + assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); + CodeBlob* cb = CodeCache::find_blob(pc); + if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { + // Not sure where the pc points to, fallback to default + // stack overflow handling. In compiled code, we bang before + // the frame is complete. + return false; + } else { + intptr_t* fp = os::Linux::ucontext_get_fp(uc); + intptr_t* sp = os::Linux::ucontext_get_sp(uc); + *fr = frame(sp, (address)*sp); + if (!fr->is_java_frame()) { + assert(fr->safe_for_sender(thread), "Safety check"); + assert(!fr->is_first_frame(), "Safety check"); + *fr = fr->java_sender(); + } + } + } + assert(fr->is_java_frame(), "Safety check"); + return true; +} + frame os::get_sender_for_C_frame(frame* fr) { if (*fr->sp() == 0) { // fr is the last C frame. @@ -279,13 +315,31 @@ JVM_handle_linux_signal(int sig, if (thread->on_local_stack(addr)) { // stack overflow if (thread->in_stack_yellow_reserved_zone(addr)) { - thread->disable_stack_yellow_reserved_zone(); if (thread->thread_state() == _thread_in_Java) { + if (thread->in_stack_reserved_zone(addr)) { + frame fr; + if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) { + assert(fr.is_java_frame(), "Must be a Javac frame"); + frame activation = + SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); + if (activation.sp() != NULL) { + thread->disable_stack_reserved_zone(); + if (activation.is_interpreted_frame()) { + thread->set_reserved_stack_activation((address)activation.fp()); + } else { + thread->set_reserved_stack_activation((address)activation.unextended_sp()); + } + return 1; + } + } + } // Throw a stack overflow exception. // Guard pages will be reenabled while unwinding the stack. + thread->disable_stack_yellow_reserved_zone(); stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); } else { // Thread was in the vm or native code. Return and try to finish. + thread->disable_stack_yellow_reserved_zone(); return 1; } } else if (thread->in_stack_red_zone(addr)) { diff --git a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp index f5c0ff370a0..5fcd2de83df 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp @@ -89,7 +89,10 @@ // Minimum usable stack sizes required to get to user code. Space for // HotSpot guard pages is added later. #ifdef _LP64 -size_t os::Posix::_compiler_thread_min_stack_allowed = 202 * K; +// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler +// threads requires a large stack with the Solaris Studio C++ compiler version 5.13 +// and product VM builds (debug builds require significantly less stack space). +size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K; size_t os::Posix::_java_thread_min_stack_allowed = 48 * K; size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K; #else diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index d9e8726bb58..3bc1fa6aec8 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -650,6 +650,7 @@ bool InstructForm::is_wide_memory_kill(FormDict &globals) const { if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true; if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true; + if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true; if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true; if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true; diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.cpp b/hotspot/src/share/vm/aot/aotCodeHeap.cpp index 08283a92fbe..52e2c8d55b1 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp @@ -25,6 +25,7 @@ #include "aot/aotCodeHeap.hpp" #include "aot/aotLoader.hpp" +#include "classfile/javaAssertions.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/shared/gcLocker.hpp" #include "interpreter/abstractInterpreter.hpp" @@ -294,6 +295,8 @@ void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data // When the AOT compiler compiles something big we fail to generate metadata // in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end. // In all successful cases we always have 2 entries of scope pcs. + log_info(aot, class, resolve)("Failed to load %s (no metadata available)", mh->name_and_sig_as_C_string()); + _code_to_aot[code_id]._state = invalid; return; } @@ -536,6 +539,7 @@ void AOTCodeHeap::link_global_lib_symbols() { SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL)); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page()); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base()); + SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, Universe::narrow_oop_base()); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc()); link_shared_runtime_symbols(); @@ -706,6 +710,12 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) { return false; } + if (_lib->config()->_omitAssertions && JavaAssertions::enabled(kh->name()->as_C_string(), kh->class_loader() == NULL)) { + log_trace(aot, class, load)("class %s in %s does not have java assertions in compiled code, but assertions are enabled for this execution.", kh->internal_name(), _lib->name()); + sweep_dependent_methods(klass_data); + return false; + } + NOT_PRODUCT( aot_klasses_found++; ) log_trace(aot, class, load)("found %s in %s for classloader %p tid=" INTPTR_FORMAT, kh->internal_name(), _lib->name(), kh->class_loader_data(), p2i(thread)); @@ -714,7 +724,7 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) { // Set klass's Resolve (second) got cell. _metaspace_got[klass_data->_got_index] = kh(); - // Initialize global symbols of the DSO to the correspondingVM symbol values. + // Initialize global symbols of the DSO to the corresponding VM symbol values. link_global_lib_symbols(); int methods_offset = klass_data->_compiled_methods_offset; diff --git a/hotspot/src/share/vm/aot/aotCodeHeap.hpp b/hotspot/src/share/vm/aot/aotCodeHeap.hpp index 21ce9a042f0..0e0d0038d10 100644 --- a/hotspot/src/share/vm/aot/aotCodeHeap.hpp +++ b/hotspot/src/share/vm/aot/aotCodeHeap.hpp @@ -88,7 +88,7 @@ typedef struct { } AOTHeader; typedef struct { - enum { CONFIG_SIZE = 11 + 7 * 4 }; + enum { CONFIG_SIZE = 12 + 7 * 4 }; int _config_size; int _narrowOopShift; int _narrowKlassShift; @@ -108,6 +108,7 @@ typedef struct { bool _tieredAOT; bool _enableContended; bool _restrictContended; + bool _omitAssertions; } AOTConfiguration; class AOTLib : public CHeapObj { diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 75a4f8aa3de..1a0a5f63687 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3298,7 +3298,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) // for osr compile, bailout if some requirements are not fulfilled if (osr_bci != -1) { BlockBegin* osr_block = blm.bci2block()->at(osr_bci); - assert(osr_block->is_set(BlockBegin::was_visited_flag),"osr entry must have been visited for osr compile"); + if (!osr_block->is_set(BlockBegin::was_visited_flag)) { + BAILOUT("osr entry must have been visited for osr compile"); + } // check if osr entry point has empty stack - we cannot handle non-empty stacks at osr entry points if (!osr_block->state()->stack_is_empty()) { diff --git a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp index f7916cb1dab..e960d142abe 100644 --- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp +++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp @@ -895,8 +895,32 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl ciMethod* target = s.get_method(ignored_will_link, &declared_signature); ciKlass* holder = s.get_declared_method_holder(); assert(declared_signature != NULL, "cannot be null"); - // Push appendix argument, if one. - if (s.has_appendix()) { + // If the current bytecode has an attached appendix argument, + // push an unknown object to represent that argument. (Analysis + // of dynamic call sites, especially invokehandle calls, needs + // the appendix argument on the stack, in addition to "regular" arguments + // pushed onto the stack by bytecode instructions preceding the call.) + // + // The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s) + // method to determine whether the current bytecode has an appendix argument. + // The has_appendix() method obtains the appendix from the + // ConstantPoolCacheEntry::_f1 field, which can happen concurrently with + // resolution of dynamic call sites. Callees in the + // ciBytecodeStream::get_method() call above also access the _f1 field; + // interleaving the get_method() and has_appendix() calls in the current + // method with call site resolution can lead to an inconsistent view of + // the current method's argument count. In particular, some interleaving(s) + // can cause the method's argument count to not include the appendix, which + // then leads to stack over-/underflow in the escape analyzer. + // + // Instead of pushing the argument if has_appendix() is true, the escape analyzer + // pushes an appendix for all call sites targeted by invokedynamic and invokehandle + // instructions, except if the call site is the _invokeBasic intrinsic + // (that intrinsic is always targeted by an invokehandle instruction but does + // not have an appendix argument). + if (target->is_loaded() && + Bytecodes::has_optional_appendix(s.cur_bc_raw()) && + target->intrinsic_id() != vmIntrinsics::_invokeBasic) { state.apush(unknown_obj); } // Pass in raw bytecode because we need to see invokehandle instructions. diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 2580f40f3ea..f16948e71d7 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -136,15 +136,19 @@ class ciMethod : public ciMetadata { check_is_loaded(); return _signature->size() + (_flags.is_static() ? 0 : 1); } - // Report the number of elements on stack when invoking this method. - // This is different than the regular arg_size because invokedynamic - // has an implicit receiver. + // Report the number of elements on stack when invoking the current method. + // If the method is loaded, arg_size() gives precise information about the + // number of stack elements (using the method's signature and its flags). + // However, if the method is not loaded, the number of stack elements must + // be determined differently, as the method's flags are not yet available. + // The invoke_arg_size() method assumes in that case that all bytecodes except + // invokestatic and invokedynamic have a receiver that is also pushed onto the + // stack by the caller of the current method. int invoke_arg_size(Bytecodes::Code code) const { if (is_loaded()) { return arg_size(); } else { int arg_size = _signature->size(); - // Add a receiver argument, maybe: if (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic) { arg_size++; diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index e0b7c84e45b..0b036181d31 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -364,7 +364,12 @@ u1* ClassPathZipEntry::open_versioned_entry(const char* name, jint* filesize, TR if (verstr != NULL) { version = atoi(verstr); if (version < base_version || version > cur_ver) { - is_multi_ver = false; + // If the specified version is lower than the base version, the base + // entry will be used; if the version is higher than the current + // jdk version, the highest versioned entry will be used. + if (version < base_version) { + is_multi_ver = false; + } // print out warning, do not use assertion here since it will continue to look // for proper version. warning("JDK%d is not supported in multiple version jars", version); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index fbafa936950..d1e37d82761 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -94,7 +94,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen _metaspace(NULL), _unloading(false), _klasses(NULL), _modules(NULL), _packages(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), - _next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1), + _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, Monitor::_safepoint_check_never)) { TRACE_INIT_ID(this); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index b69c4e681d4..8c8df5187a7 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -204,9 +204,6 @@ class ClassLoaderData : public CHeapObj { // Support for walking class loader data objects ClassLoaderData* _next; /// Next loader_datas created - // CDS - int _shared_class_loader_id; - // ReadOnly and ReadWrite metaspaces (static because only on the null // class loader for now). static Metaspace* _ro_metaspace; @@ -338,15 +335,6 @@ class ClassLoaderData : public CHeapObj { Metaspace* rw_metaspace(); void initialize_shared_metaspaces(); - int shared_class_loader_id() const { - return _shared_class_loader_id; - } - void set_shared_class_loader_id(int id) { - assert(id >= 0, "sanity"); - assert(_shared_class_loader_id <0, "cannot be assigned more than once"); - _shared_class_loader_id = id; - } - TRACE_DEFINE_TRACE_ID_METHODS; }; diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 91b51404489..b7fe590eee1 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -163,8 +163,8 @@ void java_lang_String::compute_offsets() { Klass* k = SystemDictionary::String_klass(); compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::byte_array_signature()); - compute_optional_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature()); - compute_optional_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature()); + compute_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature()); + compute_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature()); initialized = true; } @@ -3977,12 +3977,8 @@ void JavaClasses::check_offsets() { // java.lang.String CHECK_OFFSET("java/lang/String", java_lang_String, value, "[B"); - if (java_lang_String::has_hash_field()) { - CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I"); - } - if (java_lang_String::has_coder_field()) { - CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B"); - } + CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I"); + CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B"); // java.lang.Class diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 0cf0090e851..f05db4c79b7 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -81,15 +81,6 @@ class java_lang_String : AllStatic { static Handle create_from_platform_dependent_str(const char* str, TRAPS); static Handle char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS); - static bool has_hash_field() { - assert(initialized, "Must be initialized"); - return (hash_offset > 0); - } - static bool has_coder_field() { - assert(initialized, "Must be initialized"); - return (coder_offset > 0); - } - static void set_compact_strings(bool value); static int value_offset_in_bytes() { diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp index b1c4a3f9224..b388bb157d3 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp @@ -30,10 +30,8 @@ #include "oops/oopsHierarchy.hpp" void java_lang_String::set_coder(oop string, jbyte coder) { - assert(initialized, "Must be initialized"); - if (coder_offset > 0) { - string->byte_field_put(coder_offset, coder); - } + assert(initialized && (coder_offset > 0), "Must be initialized"); + string->byte_field_put(coder_offset, coder); } void java_lang_String::set_value_raw(oop string, typeArrayOop buffer) { @@ -61,15 +59,11 @@ unsigned int java_lang_String::hash(oop java_string) { return java_string->int_field(hash_offset); } bool java_lang_String::is_latin1(oop java_string) { - assert(initialized, "Must be initialized"); + assert(initialized && (coder_offset > 0), "Must be initialized"); assert(is_instance(java_string), "must be java_string"); - if (coder_offset > 0) { - jbyte coder = java_string->byte_field(coder_offset); - assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings"); - return coder == CODER_LATIN1; - } else { - return false; - } + jbyte coder = java_string->byte_field(coder_offset); + assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings"); + return coder == CODER_LATIN1; } int java_lang_String::length(oop java_string) { assert(initialized, "Must be initialized"); diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp index becda5363a6..afa3553af1c 100644 --- a/hotspot/src/share/vm/classfile/modules.cpp +++ b/hotspot/src/share/vm/classfile/modules.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,6 @@ #include "logging/log.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/objArrayOop.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" @@ -48,17 +46,17 @@ #include "utilities/stringUtils.hpp" #include "utilities/utf8.hpp" -static bool verify_module_name(char *module_name) { +static bool verify_module_name(const char *module_name) { if (module_name == NULL) return false; int len = (int)strlen(module_name); return (len > 0 && len <= Symbol::max_length()); } -bool Modules::verify_package_name(char *package_name) { +bool Modules::verify_package_name(const char* package_name) { if (package_name == NULL) return false; int len = (int)strlen(package_name); return (len > 0 && len <= Symbol::max_length() && - UTF8::is_legal_utf8((unsigned char *)package_name, len, false) && + UTF8::is_legal_utf8((const unsigned char *)package_name, len, false) && ClassFileParser::verify_unqualified_name(package_name, len, ClassFileParser::LegalClass)); } @@ -107,10 +105,8 @@ static ModuleEntry* get_module_entry(jobject module, TRAPS) { return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL); } -static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, TRAPS) { +static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, TRAPS) { ResourceMark rm(THREAD); - if (package == NULL) return NULL; - const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); if (package_name == NULL) return NULL; TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL); PackageEntryTable* package_entry_table = module_entry->loader_data()->packages(); @@ -139,7 +135,8 @@ bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) { } static void define_javabase_module(jobject module, jstring version, - jstring location, jobjectArray packages, TRAPS) { + jstring location, const char* const* packages, + jsize num_packages, TRAPS) { ResourceMark rm(THREAD); Handle module_handle(THREAD, JNIHandles::resolve(module)); @@ -164,21 +161,12 @@ static void define_javabase_module(jobject module, jstring version, } } - objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages)); - objArrayHandle packages_h(THREAD, packages_oop); - int num_packages = (packages_h == NULL ? 0 : packages_h->length()); // Check that the list of packages has no duplicates and that the // packages are syntactically ok. GrowableArray* pkg_list = new GrowableArray(num_packages); for (int x = 0; x < num_packages; x++) { - oop string_obj = packages_h->obj_at(x); - - if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Bad package name for module: " JAVA_BASE_NAME); - } - char *package_name = java_lang_String::as_utf8_string(string_obj); + const char *package_name = packages[x]; if (!Modules::verify_package_name(package_name)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name)); @@ -239,7 +227,7 @@ static void define_javabase_module(jobject module, jstring version, } } if (duplicate_javabase) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + THROW_MSG(vmSymbols::java_lang_InternalError(), "Module " JAVA_BASE_NAME " is already defined"); } @@ -262,13 +250,39 @@ static void define_javabase_module(jobject module, jstring version, } } +// Caller needs ResourceMark. +void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) { + const char* package_name = package->name()->as_C_string(); + if (package->module()->is_named()) { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), + err_msg("Package %s for module %s is already in another module, %s, defined to the class loader", + package_name, module_name, package->module()->name()->as_C_string())); + } else { + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), + err_msg("Package %s for module %s is already in the unnamed module defined to the class loader", + package_name, module_name)); + } +} + void Modules::define_module(jobject module, jstring version, - jstring location, jobjectArray packages, TRAPS) { + jstring location, const char* const* packages, + jsize num_packages, TRAPS) { ResourceMark rm(THREAD); if (module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); } + + if (num_packages < 0) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "num_packages must be >= 0"); + } + + if (packages == NULL && num_packages > 0) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "num_packages should be zero if packages is null"); + } + Handle module_handle(THREAD, JNIHandles::resolve(module)); if (!java_lang_reflect_Module::is_instance(module_handle())) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), @@ -283,7 +297,7 @@ void Modules::define_module(jobject module, jstring version, // Special handling of java.base definition if (strcmp(module_name, JAVA_BASE_NAME) == 0) { - define_javabase_module(module, version, location, packages, CHECK); + define_javabase_module(module, version, location, packages, num_packages, CHECK); return; } @@ -297,21 +311,11 @@ void Modules::define_module(jobject module, jstring version, } Handle h_loader = Handle(THREAD, loader); - objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages)); - objArrayHandle packages_h(THREAD, packages_oop); - int num_packages = (packages_h == NULL ? 0 : packages_h->length()); - // Check that the list of packages has no duplicates and that the // packages are syntactically ok. GrowableArray* pkg_list = new GrowableArray(num_packages); for (int x = 0; x < num_packages; x++) { - oop string_obj = packages_h->obj_at(x); - - if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Bad package name for module: %s", module_name)); - } - char *package_name = java_lang_String::as_utf8_string(string_obj); + const char* package_name = packages[x]; if (!verify_package_name(package_name)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid package name: %s for module: %s", @@ -323,12 +327,15 @@ void Modules::define_module(jobject module, jstring version, !SystemDictionary::is_platform_class_loader(h_loader) && strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) { const char* class_loader_name = SystemDictionary::loader_name(h_loader()); - StringUtils::replace_no_expand(package_name, "/", "."); + size_t pkg_len = strlen(package_name); + char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len); + strncpy(pkg_name, package_name, pkg_len); + StringUtils::replace_no_expand(pkg_name, "/", "."); const char* msg_text1 = "Class loader (instance of): "; const char* msg_text2 = " tried to define prohibited package name: "; - size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1; + size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1; char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); - jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name); + jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message); } @@ -347,7 +354,6 @@ void Modules::define_module(jobject module, jstring version, // Create symbol* entry for module name. TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK); - int dupl_pkg_index = -1; bool dupl_modules = false; // Create symbol* entry for module version. @@ -373,6 +379,7 @@ void Modules::define_module(jobject module, jstring version, assert(loader_data != NULL, "class loader data shouldn't be null"); PackageEntryTable* package_table = NULL; + PackageEntry* existing_pkg = NULL; { MutexLocker ml(Module_lock, THREAD); @@ -382,13 +389,12 @@ void Modules::define_module(jobject module, jstring version, // Check that none of the packages exist in the class loader's package table. for (int x = 0; x < pkg_list->length(); x++) { - if (package_table->lookup_only(pkg_list->at(x)) != NULL) { + existing_pkg = package_table->lookup_only(pkg_list->at(x)); + if (existing_pkg != NULL) { // This could be because the module was already defined. If so, // report that error instead of the package error. if (module_table->lookup_only(module_symbol) != NULL) { dupl_modules = true; - } else { - dupl_pkg_index = x; } break; } @@ -396,9 +402,8 @@ void Modules::define_module(jobject module, jstring version, } // if (num_packages > 0)... // Add the module and its packages. - if (!dupl_modules && dupl_pkg_index == -1) { + if (!dupl_modules && existing_pkg == NULL) { // Create the entry for this module in the class loader's module entry table. - ModuleEntry* module_entry = module_table->locked_create_entry_or_null(module_handle, module_symbol, version_symbol, location_symbol, loader_data); @@ -426,13 +431,10 @@ void Modules::define_module(jobject module, jstring version, // any errors ? if (dupl_modules) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + THROW_MSG(vmSymbols::java_lang_IllegalStateException(), err_msg("Module %s is already defined", module_name)); - } - if (dupl_pkg_index != -1) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Package %s for module %s already exists for class loader", - pkg_list->at(dupl_pkg_index)->as_C_string(), module_name)); + } else if (existing_pkg != NULL) { + throw_dup_pkg_exception(module_name, existing_pkg, CHECK); } if (log_is_enabled(Debug, modules)) { @@ -497,8 +499,8 @@ void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) { java_lang_reflect_Module::set_module_entry(module_handle(), unnamed_module); } -void Modules::add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS) { - if (package == NULL) { +void Modules::add_module_exports(jobject from_module, const char* package_name, jobject to_module, TRAPS) { + if (package_name == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "package is null"); } @@ -526,10 +528,9 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t } } - PackageEntry *package_entry = get_package_entry(from_module_entry, package, CHECK); + PackageEntry *package_entry = get_package_entry(from_module_entry, package_name, CHECK); ResourceMark rm(THREAD); if (package_entry == NULL) { - const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Package %s not found in from_module %s", package_name != NULL ? package_name : "", @@ -557,7 +558,7 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t } -void Modules::add_module_exports_qualified(jobject from_module, jstring package, +void Modules::add_module_exports_qualified(jobject from_module, const char* package, jobject to_module, TRAPS) { if (to_module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), @@ -649,21 +650,15 @@ jobject Modules::get_module(jclass clazz, TRAPS) { } -jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) { +jobject Modules::get_module_by_package_name(jobject loader, const char* package_name, TRAPS) { ResourceMark rm(THREAD); assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_module_from_pkg before " JAVA_BASE_NAME " is defined"); - if (NULL == package) { + if (package_name == NULL) { THROW_MSG_(vmSymbols::java_lang_NullPointerException(), "package is null", JNI_FALSE); } - const char* package_str = - java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); - if (NULL == package_str) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "Invalid package", JNI_FALSE); - } Handle h_loader (THREAD, JNIHandles::resolve(loader)); // Check that loader is a subclass of java.lang.ClassLoader. @@ -672,7 +667,7 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA "Class loader is not a subclass of java.lang.ClassLoader", JNI_FALSE); } - if (strlen(package_str) == 0) { + if (strlen(package_name) == 0) { // Return the unnamed module ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK_NULL); if (NULL == module_table) return NULL; @@ -680,24 +675,24 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA return JNIHandles::make_local(THREAD, JNIHandles::resolve(unnamed_module->module())); } else { - TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL); + TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL); return get_module(package_sym, h_loader, CHECK_NULL); } return NULL; } -jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) { +jobject Modules::get_named_module(Handle h_loader, const char* package_name, TRAPS) { assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_named_module before " JAVA_BASE_NAME " is defined"); assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()), "Class loader is not a subclass of java.lang.ClassLoader"); - assert(package_str != NULL, "the package_str should not be NULL"); + assert(package_name != NULL, "the package_name should not be NULL"); - if (strlen(package_str) == 0) { + if (strlen(package_name) == 0) { return NULL; } - TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL); + TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL); const PackageEntry* const pkg_entry = get_package_entry_by_name(package_sym, h_loader, THREAD); const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL); @@ -723,14 +718,14 @@ jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) { return NULL; } -void Modules::add_module_package(jobject module, jstring package, TRAPS) { +void Modules::add_module_package(jobject module, const char* package_name, TRAPS) { ResourceMark rm(THREAD); if (module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "module is null"); } - if (package == NULL) { + if (package_name == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "package is null"); } @@ -743,11 +738,6 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "module cannot be an unnamed module"); } - char *package_name = java_lang_String::as_utf8_string( - JNIHandles::resolve_non_null(package)); - if (package_name == NULL) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad package"); - } if (!verify_package_name(package_name)) { THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Invalid package name: %s", package_name)); @@ -760,12 +750,15 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { !loader_data->is_platform_class_loader_data() && strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) { const char* class_loader_name = SystemDictionary::loader_name(loader_data); - StringUtils::replace_no_expand(package_name, "/", "."); + size_t pkg_len = strlen(package_name); + char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len); + strncpy(pkg_name, package_name, pkg_len); + StringUtils::replace_no_expand(pkg_name, "/", "."); const char* msg_text1 = "Class loader (instance of): "; const char* msg_text2 = " tried to define prohibited package name: "; - size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1; + size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1; char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len); - jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name); + jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message); } @@ -776,31 +769,29 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) { PackageEntryTable* package_table = loader_data->packages(); assert(package_table != NULL, "Missing package_table"); - bool pkg_exists = false; + PackageEntry* existing_pkg = NULL; { MutexLocker ml(Module_lock, THREAD); // Check that the package does not exist in the class loader's package table. - if (!package_table->lookup_only(pkg_symbol)) { + existing_pkg = package_table->lookup_only(pkg_symbol); + if (existing_pkg == NULL) { PackageEntry* pkg = package_table->locked_create_entry_or_null(pkg_symbol, module_entry); assert(pkg != NULL, "Unable to create a module's package entry"); - } else { - pkg_exists = true; } } - if (pkg_exists) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - err_msg("Package %s already exists for class loader", package_name)); + if (existing_pkg != NULL) { + throw_dup_pkg_exception(module_entry->name()->as_C_string(), existing_pkg, CHECK); } } // Export package in module to all unnamed modules. -void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS) { +void Modules::add_module_exports_to_all_unnamed(jobject module, const char* package_name, TRAPS) { if (module == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "module is null"); } - if (package == NULL) { + if (package_name == NULL) { THROW_MSG(vmSymbols::java_lang_NullPointerException(), "package is null"); } @@ -811,10 +802,9 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, } if (module_entry->is_named()) { // No-op for unnamed module. - PackageEntry *package_entry = get_package_entry(module_entry, package, CHECK); + PackageEntry *package_entry = get_package_entry(module_entry, package_name, CHECK); ResourceMark rm(THREAD); if (package_entry == NULL) { - const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package)); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), err_msg("Package %s not found in module %s", package_name != NULL ? package_name : "", @@ -833,10 +823,7 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, package_entry->name()->as_C_string(), module_entry->name()->as_C_string()); - // Mark package as exported to all unnamed modules, unless already - // unqualifiedly exported. - if (!package_entry->is_unqual_exported()) { - package_entry->set_is_exported_allUnnamed(); - } + // Mark package as exported to all unnamed modules. + package_entry->set_is_exported_allUnnamed(); } } diff --git a/hotspot/src/share/vm/classfile/modules.hpp b/hotspot/src/share/vm/classfile/modules.hpp index 25d02bf845c..4f5e089a065 100644 --- a/hotspot/src/share/vm/classfile/modules.hpp +++ b/hotspot/src/share/vm/classfile/modules.hpp @@ -48,9 +48,12 @@ public: // * Packages contains a duplicate package name // * A package already exists in another module for this class loader // * Module is an unnamed module + // * num_packages is negative + // * num_packages is non-zero when packages is null // NullPointerExceptions are thrown if module is null. static void define_module(jobject module, jstring version, - jstring location, jobjectArray packages, TRAPS); + jstring location, const char* const* packages, + jsize num_packages, TRAPS); // Provides the java.lang.reflect.Module for the unnamed module defined // to the boot loader. @@ -72,7 +75,7 @@ public: // * Package is not syntactically correct // * Package is not defined for from_module's class loader // * Package is not in module from_module. - static void add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS); + static void add_module_exports(jobject from_module, const char* package, jobject to_module, TRAPS); // This does a qualified export of package in module from_module to module // to_module. The format for the package name must use "/' not ".". @@ -83,7 +86,7 @@ public: // * Package is not syntactically correct // * Package is not defined for from_module's class loader // * Package is not in module from_module. - static void add_module_exports_qualified(jobject from_module, jstring package, jobject to_module, TRAPS); + static void add_module_exports_qualified(jobject from_module, const char* package, jobject to_module, TRAPS); // add_reads_module adds module to_module to the list of modules that from_module // can read. If from_module is the same as to_module then this is a no-op. @@ -102,7 +105,7 @@ public: // NullPointerException is thrown if package is null. // IllegalArgumentException is thrown if loader is neither null nor a subtype of // java/lang/ClassLoader. - static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS); + static jobject get_module_by_package_name(jobject loader, const char* package, TRAPS); static jobject get_named_module(Handle h_loader, const char* package, TRAPS); // If package is defined by loader, return the @@ -116,16 +119,16 @@ public: // * Module is unnamed // * Package is not syntactically correct // * Package is already defined for module's class loader. - static void add_module_package(jobject module, jstring package, TRAPS); + static void add_module_package(jobject module, const char* package, TRAPS); // Marks the specified package as exported to all unnamed modules. // If either module or package is null then NullPointerException is thrown. // If module or package is bad, or module is unnamed, or package is not in // module then IllegalArgumentException is thrown. - static void add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS); + static void add_module_exports_to_all_unnamed(jobject module, const char* package, TRAPS); // Return TRUE if package_name is syntactically valid, false otherwise. - static bool verify_package_name(char *package_name); + static bool verify_package_name(const char *package_name); // Return TRUE iff package is defined by loader static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS); diff --git a/hotspot/src/share/vm/classfile/packageEntry.cpp b/hotspot/src/share/vm/classfile/packageEntry.cpp index 7ee6c52dd4e..ab80fcb732b 100644 --- a/hotspot/src/share/vm/classfile/packageEntry.cpp +++ b/hotspot/src/share/vm/classfile/packageEntry.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,8 +37,8 @@ // Returns true if this package specifies m as a qualified export, including through an unnamed export bool PackageEntry::is_qexported_to(ModuleEntry* m) const { + assert(Module_lock->owned_by_self(), "should have the Module_lock"); assert(m != NULL, "No module to lookup in this package's qualified exports list"); - MutexLocker m1(Module_lock); if (is_exported_allUnnamed() && !m->is_named()) { return true; } else if (!has_qual_exports_list()) { @@ -98,15 +98,8 @@ void PackageEntry::set_exported(ModuleEntry* m) { } if (m == NULL) { - // NULL indicates the package is being unqualifiedly exported - if (has_qual_exports_list()) { - // Legit to transition a package from being qualifiedly exported - // to unqualified. Clean up the qualified lists at the next - // safepoint. - _exported_pending_delete = _qualified_exports; - } - - // Mark package as unqualifiedly exported + // NULL indicates the package is being unqualifiedly exported. Clean up + // the qualified list at the next safepoint. set_unqual_exported(); } else { @@ -115,14 +108,19 @@ void PackageEntry::set_exported(ModuleEntry* m) { } } +// Set the package as exported to all unnamed modules unless the package is +// already unqualifiedly exported. void PackageEntry::set_is_exported_allUnnamed() { MutexLocker m1(Module_lock); if (!is_unqual_exported()) { - _is_exported_allUnnamed = true; + _export_flags = PKG_EXP_ALLUNNAMED; } } -// Remove dead module entries within the package's exported list. +// Remove dead module entries within the package's exported list. Note that +// if all of the modules on the _qualified_exports get purged the list does not +// get deleted. This prevents the package from illegally transitioning from +// exported to non-exported. void PackageEntry::purge_qualified_exports() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); if (_must_walk_exports && @@ -160,18 +158,9 @@ void PackageEntry::purge_qualified_exports() { void PackageEntry::delete_qualified_exports() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - if (_exported_pending_delete != NULL) { - // If a transition occurred from qualified to unqualified, the _qualified_exports - // field should have been NULL'ed out. - assert(_qualified_exports == NULL, "Package's exported pending delete, exported list should not be active"); - delete _exported_pending_delete; - } - if (_qualified_exports != NULL) { delete _qualified_exports; } - - _exported_pending_delete = NULL; _qualified_exports = NULL; } @@ -314,6 +303,11 @@ void PackageEntry::package_exports_do(ModuleClosure* const f) { } } +bool PackageEntry::exported_pending_delete() const { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + return (is_unqual_exported() && _qualified_exports != NULL); +} + // Remove dead entries from all packages' exported list void PackageEntryTable::purge_all_package_exports() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); @@ -344,13 +338,17 @@ void PackageEntryTable::print(outputStream* st) { } } +// This function may be called from debuggers so access private fields directly +// to prevent triggering locking-related asserts that could result from calling +// getter methods. void PackageEntry::print(outputStream* st) { ResourceMark rm; st->print_cr("package entry " PTR_FORMAT " name %s module %s classpath_index " INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next " PTR_FORMAT, p2i(this), name()->as_C_string(), (module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE), - _classpath_index, _is_exported_unqualified, _is_exported_allUnnamed, p2i(next())); + _classpath_index, _export_flags == PKG_EXP_UNQUALIFIED, + _export_flags == PKG_EXP_ALLUNNAMED, p2i(next())); } void PackageEntryTable::verify() { diff --git a/hotspot/src/share/vm/classfile/packageEntry.hpp b/hotspot/src/share/vm/classfile/packageEntry.hpp index a379bf9de3b..aaafa54bb6d 100644 --- a/hotspot/src/share/vm/classfile/packageEntry.hpp +++ b/hotspot/src/share/vm/classfile/packageEntry.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,8 +34,8 @@ // A PackageEntry basically represents a Java package. It contains: // - Symbol* containing the package's name. // - ModuleEntry* for this package's containing module. -// - a flag indicating if package is exported unqualifiedly -// - a flag indicating if this package is exported to all unnamed modules. +// - a field indicating if the package is exported unqualifiedly or to all +// unnamed modules. // - a growable array containing other module entries that this // package is exported to. // @@ -44,9 +44,9 @@ // - qualified exports: the package has been explicitly qualified to at least // one particular module or has been qualifiedly exported // to all unnamed modules. -// Note: _is_exported_allUnnamed is a form of a qualified -// export. It is equivalent to the package being -// explicitly exported to all current and future unnamed modules. +// Note: being exported to all unnamed is a form of a qualified +// export. It is equivalent to the package being explicitly +// exported to all current and future unnamed modules. // - unqualified exports: the package is exported to all modules. // // A package can transition from: @@ -56,21 +56,53 @@ // A package cannot transition from: // - being unqualifiedly exported, to exported qualifiedly to a specific module. // This transition attempt is silently ignored in set_exported. +// - being qualifiedly exported to not exported. +// Because transitions are only allowed from less exposure to greater exposure, +// the transition from qualifiedly exported to not exported would be considered +// a backward direction. Therefore the implementation considers a package as +// qualifiedly exported even if its export-list exists but is empty. // // The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either // data structure. + +// PKG_EXP_UNQUALIFIED and PKG_EXP_ALLUNNAMED indicate whether the package is +// exported unqualifiedly or exported to all unnamed modules. They are used to +// set the value of _export_flags. Field _export_flags and the _qualified_exports +// list are used to determine a package's export state. +// Valid states are: +// +// 1. Package is not exported +// _export_flags is zero and _qualified_exports is null +// 2. Package is unqualifiedly exported +// _export_flags is set to PKG_EXP_UNQUALIFIED +// _qualified_exports may or may not be null depending on whether the package +// transitioned from qualifiedly exported to unqualifiedly exported. +// 3. Package is qualifiedly exported +// _export_flags may be set to PKG_EXP_ALLUNNAMED if the package is also +// exported to all unnamed modules +// _qualified_exports will be non-null +// 4. Package is exported to all unnamed modules +// _export_flags is set to PKG_EXP_ALLUNNAMED +// _qualified_exports may or may not be null depending on whether the package +// is also qualifiedly exported to one or more named modules. +#define PKG_EXP_UNQUALIFIED 0x0001 +#define PKG_EXP_ALLUNNAMED 0x0002 +#define PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED (PKG_EXP_UNQUALIFIED | PKG_EXP_ALLUNNAMED) + class PackageEntry : public HashtableEntry { private: ModuleEntry* _module; + // Indicates if package is exported unqualifiedly or to all unnamed. Access to + // this field is protected by the Module_lock. + int _export_flags; // Used to indicate for packages with classes loaded by the boot loader that // a class in that package has been loaded. And, for packages with classes // loaded by the boot loader from -Xbootclasspath/a in an unnamed module, it // indicates from which class path entry. s2 _classpath_index; - bool _is_exported_unqualified; - bool _is_exported_allUnnamed; bool _must_walk_exports; - GrowableArray* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint + // Contains list of modules this package is qualifiedly exported to. Access + // to this list is protected by the Module_lock. GrowableArray* _qualified_exports; TRACE_DEFINE_TRACE_ID_FIELD; @@ -80,17 +112,14 @@ private: public: void init() { _module = NULL; + _export_flags = 0; _classpath_index = -1; - _is_exported_unqualified = false; - _is_exported_allUnnamed = false; _must_walk_exports = false; - _exported_pending_delete = NULL; _qualified_exports = NULL; } // package name Symbol* name() const { return literal(); } - void set_name(Symbol* n) { set_literal(n); } // the module containing the package definition ModuleEntry* module() const { return _module; } @@ -98,37 +127,39 @@ public: // package's export state bool is_exported() const { // qualifiedly or unqualifiedly exported - return (is_unqual_exported() || has_qual_exports_list() || is_exported_allUnnamed()); + assert_locked_or_safepoint(Module_lock); + return ((_export_flags & PKG_EXP_UNQUALIFIED_OR_ALL_UNAMED) != 0) || has_qual_exports_list(); } // Returns true if the package has any explicit qualified exports or is exported to all unnamed bool is_qual_exported() const { + assert_locked_or_safepoint(Module_lock); return (has_qual_exports_list() || is_exported_allUnnamed()); } - // Returns true if there are any explicit qualified exports + // Returns true if there are any explicit qualified exports. Note that even + // if the _qualified_exports list is now empty (because the modules that were + // on the list got gc-ed and deleted from the list) this method may still + // return true. bool has_qual_exports_list() const { - assert(!(_qualified_exports != NULL && _is_exported_unqualified), - "_qualified_exports set at same time as _is_exported_unqualified"); - return (_qualified_exports != NULL); + assert_locked_or_safepoint(Module_lock); + return (!is_unqual_exported() && _qualified_exports != NULL); } bool is_exported_allUnnamed() const { - assert(!(_is_exported_allUnnamed && _is_exported_unqualified), - "_is_exported_allUnnamed set at same time as _is_exported_unqualified"); - return _is_exported_allUnnamed; + assert_locked_or_safepoint(Module_lock); + return (_export_flags == PKG_EXP_ALLUNNAMED); } bool is_unqual_exported() const { - assert(!(_qualified_exports != NULL && _is_exported_unqualified), - "_qualified_exports set at same time as _is_exported_unqualified"); - assert(!(_is_exported_allUnnamed && _is_exported_unqualified), - "_is_exported_allUnnamed set at same time as _is_exported_unqualified"); - return _is_exported_unqualified; + assert_locked_or_safepoint(Module_lock); + return (_export_flags == PKG_EXP_UNQUALIFIED); } + + // Explicitly set _export_flags to PKG_EXP_UNQUALIFIED and clear + // PKG_EXP_ALLUNNAMED, if it was set. void set_unqual_exported() { assert(Module_lock->owned_by_self(), "should have the Module_lock"); - _is_exported_unqualified = true; - _is_exported_allUnnamed = false; - _qualified_exports = NULL; + _export_flags = PKG_EXP_UNQUALIFIED; } - bool exported_pending_delete() const { return (_exported_pending_delete != NULL); } + + bool exported_pending_delete() const; void set_exported(ModuleEntry* m); diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp index 4da4869cef2..764e1eaa348 100644 --- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp @@ -29,7 +29,6 @@ #include "classfile/dictionary.hpp" class ClassFileStream; -class SerializeClosure; class SystemDictionaryShared: public SystemDictionary { public: @@ -79,8 +78,6 @@ public: return NULL; } - static void serialize(SerializeClosure* soc) {} - // The (non-application) CDS implementation supports only classes in the boot // class loader, which ensures that the verification constraints are the same // during archive creation time and runtime. Thus we can do the constraint checks diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 3e902d9f18e..0ef86447c4e 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -590,11 +590,11 @@ template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \ template(java_lang_management_MemoryUsage, "java/lang/management/MemoryUsage") \ template(java_lang_management_ThreadInfo, "java/lang/management/ThreadInfo") \ + template(jdk_internal_agent_Agent, "jdk/internal/agent/Agent") \ template(sun_management_Sensor, "sun/management/Sensor") \ - template(sun_management_Agent, "sun/management/Agent") \ + template(sun_management_ManagementFactoryHelper, "sun/management/ManagementFactoryHelper") \ template(com_sun_management_internal_DiagnosticCommandImpl, "com/sun/management/internal/DiagnosticCommandImpl") \ template(com_sun_management_internal_GarbageCollectorExtImpl,"com/sun/management/internal/GarbageCollectorExtImpl") \ - template(sun_management_ManagementFactoryHelper, "sun/management/ManagementFactoryHelper") \ template(getDiagnosticCommandMBean_name, "getDiagnosticCommandMBean") \ template(getDiagnosticCommandMBean_signature, "()Lcom/sun/management/DiagnosticCommandMBean;") \ template(getGcInfoBuilder_name, "getGcInfoBuilder") \ diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index 80ce54f847e..bfe643ab683 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -149,16 +149,17 @@ void CodeCache::check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t total_size = non_nmethod_size + profiled_size + non_profiled_size; // Prepare error message const char* error = "Invalid code heap sizes"; - err_msg message("NonNMethodCodeHeapSize (%zuK) + ProfiledCodeHeapSize (%zuK) + NonProfiledCodeHeapSize (%zuK) = %zuK", + err_msg message("NonNMethodCodeHeapSize (" SIZE_FORMAT "K) + ProfiledCodeHeapSize (" SIZE_FORMAT "K)" + " + NonProfiledCodeHeapSize (" SIZE_FORMAT "K) = " SIZE_FORMAT "K", non_nmethod_size/K, profiled_size/K, non_profiled_size/K, total_size/K); if (total_size > cache_size) { // Some code heap sizes were explicitly set: total_size must be <= cache_size - message.append(" is greater than ReservedCodeCacheSize (%zuK).", cache_size/K); + message.append(" is greater than ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); vm_exit_during_initialization(error, message); } else if (all_set && total_size != cache_size) { // All code heap sizes were explicitly set: total_size must equal cache_size - message.append(" is not equal to ReservedCodeCacheSize (%zuK).", cache_size/K); + message.append(" is not equal to ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); vm_exit_during_initialization(error, message); } } @@ -267,7 +268,7 @@ void CodeCache::initialize_heaps() { uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); if (non_nmethod_size < (min_code_cache_size + code_buffers_size)) { vm_exit_during_initialization(err_msg( - "Not enough space in non-nmethod code heap to run VM: %zuK < %zuK", + "Not enough space in non-nmethod code heap to run VM: " SIZE_FORMAT "K < " SIZE_FORMAT "K", non_nmethod_size/K, (min_code_cache_size + code_buffers_size)/K)); } diff --git a/hotspot/src/share/vm/code/compiledMethod.hpp b/hotspot/src/share/vm/code/compiledMethod.hpp index 863e8cfa610..f260835384a 100644 --- a/hotspot/src/share/vm/code/compiledMethod.hpp +++ b/hotspot/src/share/vm/code/compiledMethod.hpp @@ -250,7 +250,11 @@ public: address insts_begin() const { return code_begin(); } address insts_end() const { return stub_begin(); } + // Returns true if a given address is in the 'insts' section. The method + // insts_contains_inclusive() is end-inclusive. bool insts_contains(address addr) const { return insts_begin() <= addr && addr < insts_end(); } + bool insts_contains_inclusive(address addr) const { return insts_begin() <= addr && addr <= insts_end(); } + int insts_size() const { return insts_end() - insts_begin(); } virtual address consts_begin() const = 0; diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp index a0d379773eb..00c2e64f851 100644 --- a/hotspot/src/share/vm/compiler/compilerDefinitions.cpp +++ b/hotspot/src/share/vm/compiler/compilerDefinitions.cpp @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "runtime/globals.hpp" +#include "runtime/globals_extension.hpp" #include "compiler/compilerDefinitions.hpp" const char* compilertype2name_tab[compiler_number_of_types] = { @@ -32,3 +34,82 @@ const char* compilertype2name_tab[compiler_number_of_types] = { "jvmci", "shark" }; + +#if defined(COMPILER2) || defined(SHARK) +CompLevel CompLevel_highest_tier = CompLevel_full_optimization; // pure C2 and tiered or JVMCI and tiered +#elif defined(COMPILER1) +CompLevel CompLevel_highest_tier = CompLevel_simple; // pure C1 or JVMCI +#else +CompLevel CompLevel_highest_tier = CompLevel_none; +#endif + +#if defined(TIERED) +CompLevel CompLevel_initial_compile = CompLevel_full_profile; // tiered +#elif defined(COMPILER1) || INCLUDE_JVMCI +CompLevel CompLevel_initial_compile = CompLevel_simple; // pure C1 or JVMCI +#elif defined(COMPILER2) || defined(SHARK) +CompLevel CompLevel_initial_compile = CompLevel_full_optimization; // pure C2 +#else +CompLevel CompLevel_initial_compile = CompLevel_none; +#endif + +#if defined(COMPILER2) +CompMode Compilation_mode = CompMode_server; +#elif defined(COMPILER1) +CompMode Compilation_mode = CompMode_client; +#else +CompMode Compilation_mode = CompMode_none; +#endif + +#ifdef TIERED +void set_client_compilation_mode() { + Compilation_mode = CompMode_client; + CompLevel_highest_tier = CompLevel_simple; + CompLevel_initial_compile = CompLevel_simple; + FLAG_SET_ERGO(bool, TieredCompilation, false); + FLAG_SET_ERGO(bool, ProfileInterpreter, false); +#if INCLUDE_JVMCI + FLAG_SET_ERGO(bool, EnableJVMCI, false); + FLAG_SET_ERGO(bool, UseJVMCICompiler, false); +#endif +#if INCLUDE_AOT + FLAG_SET_ERGO(bool, UseAOT, false); +#endif + if (FLAG_IS_DEFAULT(NeverActAsServerClassMachine)) { + FLAG_SET_ERGO(bool, NeverActAsServerClassMachine, true); + } + if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) { + FLAG_SET_ERGO(uintx, InitialCodeCacheSize, 160*K); + } + if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) { + FLAG_SET_ERGO(uintx, ReservedCodeCacheSize, 32*M); + } + if (FLAG_IS_DEFAULT(NonProfiledCodeHeapSize)) { + FLAG_SET_ERGO(uintx, NonProfiledCodeHeapSize, 27*M); + } + if (FLAG_IS_DEFAULT(ProfiledCodeHeapSize)) { + FLAG_SET_ERGO(uintx, ProfiledCodeHeapSize, 0); + } + if (FLAG_IS_DEFAULT(NonNMethodCodeHeapSize)) { + FLAG_SET_ERGO(uintx, NonNMethodCodeHeapSize, 5*M); + } + if (FLAG_IS_DEFAULT(CodeCacheExpansionSize)) { + FLAG_SET_ERGO(uintx, CodeCacheExpansionSize, 32*K); + } + if (FLAG_IS_DEFAULT(MetaspaceSize)) { + FLAG_SET_ERGO(size_t, MetaspaceSize, 12*M); + } + if (FLAG_IS_DEFAULT(MaxRAM)) { + FLAG_SET_ERGO(uint64_t, MaxRAM, 1ULL*G); + } + if (FLAG_IS_DEFAULT(CompileThreshold)) { + FLAG_SET_ERGO(intx, CompileThreshold, 1500); + } + if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) { + FLAG_SET_ERGO(intx, OnStackReplacePercentage, 933); + } + if (FLAG_IS_DEFAULT(CICompilerCount)) { + FLAG_SET_ERGO(intx, CICompilerCount, 1); + } +} +#endif // TIERED diff --git a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp index 9a08a97b303..a2378ea1e92 100644 --- a/hotspot/src/share/vm/compiler/compilerDefinitions.hpp +++ b/hotspot/src/share/vm/compiler/compilerDefinitions.hpp @@ -54,27 +54,30 @@ enum CompLevel { CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4, // C2, Shark or JVMCI - -#if defined(COMPILER2) || defined(SHARK) - CompLevel_highest_tier = CompLevel_full_optimization, // pure C2 and tiered or JVMCI and tiered -#elif defined(COMPILER1) - CompLevel_highest_tier = CompLevel_simple, // pure C1 or JVMCI -#else - CompLevel_highest_tier = CompLevel_none, -#endif - -#if defined(TIERED) - CompLevel_initial_compile = CompLevel_full_profile // tiered -#elif defined(COMPILER1) || INCLUDE_JVMCI - CompLevel_initial_compile = CompLevel_simple // pure C1 or JVMCI -#elif defined(COMPILER2) || defined(SHARK) - CompLevel_initial_compile = CompLevel_full_optimization // pure C2 -#else - CompLevel_initial_compile = CompLevel_none -#endif + CompLevel_full_optimization = 4 // C2, Shark or JVMCI }; +extern CompLevel CompLevel_highest_tier; +extern CompLevel CompLevel_initial_compile; + +enum CompMode { + CompMode_none = 0, + CompMode_client = 1, + CompMode_server = 2 +}; + +extern CompMode Compilation_mode; + +inline bool is_server_compilation_mode_vm() { + return Compilation_mode == CompMode_server; +} + +inline bool is_client_compilation_mode_vm() { + return Compilation_mode == CompMode_client; +} + +extern void set_client_compilation_mode(); + inline bool is_c1_compile(int comp_level) { return comp_level > CompLevel_none && comp_level < CompLevel_full_optimization; } diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index ed224cea90f..4388f348e92 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -445,7 +445,9 @@ void DirectivesStack::init() { _default_directives->_c1_store->EnableOption = true; #endif #ifdef COMPILER2 - _default_directives->_c2_store->EnableOption = true; + if (is_server_compilation_mode_vm()) { + _default_directives->_c2_store->EnableOption = true; + } #endif assert(error_msg == NULL, "Must succeed."); push(_default_directives); diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp index 283fd48127e..7c4efa650a5 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -60,13 +60,12 @@ cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \ cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \ cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \ - cflags(TraceOptoPipelining, bool, false, TraceOptoPipelining) \ - cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \ +NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipelining)) \ +NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ - cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \ cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #else diff --git a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp index 42069703b27..93b07b21e2d 100644 --- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp +++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,12 +69,12 @@ protected: void initialize(HeapWord* bottom, HeapWord* end, size_t target_elem_size_in_bytes, size_t mapping_granularity_in_bytes) { assert(mapping_granularity_in_bytes > 0, "just checking"); assert(is_power_of_2(mapping_granularity_in_bytes), - "mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes); + "mapping granularity must be power of 2, is " SIZE_FORMAT, mapping_granularity_in_bytes); assert((uintptr_t)bottom % mapping_granularity_in_bytes == 0, - "bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + "bottom mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT, mapping_granularity_in_bytes, p2i(bottom)); assert((uintptr_t)end % mapping_granularity_in_bytes == 0, - "end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT, + "end mapping area address must be a multiple of mapping granularity " SIZE_FORMAT ", is " PTR_FORMAT, mapping_granularity_in_bytes, p2i(end)); size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes); idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes; diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index 4f2c46913db..737c57c117d 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -233,7 +233,7 @@ void CollectedHeap::pre_initialize() { // Used for ReduceInitialCardMarks (when COMPILER2 is used); // otherwise remains unused. #if defined(COMPILER2) || INCLUDE_JVMCI - _defer_initial_card_mark = ReduceInitialCardMarks && can_elide_tlab_store_barriers() + _defer_initial_card_mark = is_server_compilation_mode_vm() && ReduceInitialCardMarks && can_elide_tlab_store_barriers() && (DeferInitialCardMark || card_mark_must_follow_store()); #else assert(_defer_initial_card_mark == false, "Who would set it?"); diff --git a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp index 5248654f2f7..0119e115104 100644 --- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp @@ -1209,7 +1209,7 @@ void GenCollectedHeap::gc_epilogue(bool full) { #if defined(COMPILER2) || INCLUDE_JVMCI assert(DerivedPointerTable::is_empty(), "derived pointer present"); size_t actual_gap = pointer_delta((HeapWord*) (max_uintx-3), *(end_addr())); - guarantee(actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); + guarantee(is_client_compilation_mode_vm() || actual_gap > (size_t)FastAllocateSizeLimit, "inline allocation wraps"); #endif /* COMPILER2 || INCLUDE_JVMCI */ resize_all_tlabs(); diff --git a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp index 38df96ddd4c..5d6d160a4ee 100644 --- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp +++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp @@ -57,11 +57,11 @@ void ReferenceProcessor::init_statics() { java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock); _always_clear_soft_ref_policy = new AlwaysClearPolicy(); -#if defined(COMPILER2) || INCLUDE_JVMCI - _default_soft_ref_policy = new LRUMaxHeapPolicy(); -#else - _default_soft_ref_policy = new LRUCurrentHeapPolicy(); -#endif + if (is_server_compilation_mode_vm()) { + _default_soft_ref_policy = new LRUMaxHeapPolicy(); + } else { + _default_soft_ref_policy = new LRUCurrentHeapPolicy(); + } if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { vm_exit_during_initialization("Could not allocate reference policy object"); } diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp index 0df1ba020a2..b004ba58c89 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.cpp @@ -233,9 +233,11 @@ void ThreadLocalAllocBuffer::startup_initialization() { // If the C2 compiler is not present, no space is reserved. // +1 for rounding up to next cache line, +1 to be safe - int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; - _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / - (int)HeapWordSize; + if (is_server_compilation_mode_vm()) { + int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; + _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / + (int)HeapWordSize; + } #endif // During jvm startup, the main (primordial) thread is initialized diff --git a/hotspot/src/share/vm/interpreter/bytecode.cpp b/hotspot/src/share/vm/interpreter/bytecode.cpp index 80b95d627b5..6cc38a5a0cd 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.cpp +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ void Bytecode::assert_native_index(Bytecodes::Code bc, bool is_wide) { // Implementation of Bytecode_tableupswitch int Bytecode_tableswitch::dest_offset_at(int i) const { - return get_Java_u4_at(aligned_offset(1 + (3 + i)*jintSize)); + return get_aligned_Java_u4_at(1 + (3 + i)*jintSize); } diff --git a/hotspot/src/share/vm/interpreter/bytecode.hpp b/hotspot/src/share/vm/interpreter/bytecode.hpp index f3fc9ea9d6a..5c53ab4121f 100644 --- a/hotspot/src/share/vm/interpreter/bytecode.hpp +++ b/hotspot/src/share/vm/interpreter/bytecode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,11 +45,11 @@ class Bytecode: public StackObj { address addr_at (int offset) const { return (address)_bcp + offset; } u_char byte_at(int offset) const { return *addr_at(offset); } address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); } - int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); } // Word access: int get_Java_u2_at (int offset) const { return Bytes::get_Java_u2(addr_at(offset)); } int get_Java_u4_at (int offset) const { return Bytes::get_Java_u4(addr_at(offset)); } + int get_aligned_Java_u4_at(int offset) const { return Bytes::get_Java_u4(aligned_addr_at(offset)); } int get_native_u2_at (int offset) const { return Bytes::get_native_u2(addr_at(offset)); } int get_native_u4_at (int offset) const { return Bytes::get_native_u4(addr_at(offset)); } @@ -150,8 +150,8 @@ class Bytecode_lookupswitch: public Bytecode { void verify() const PRODUCT_RETURN; // Attributes - int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } - int number_of_pairs() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } + int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); } + int number_of_pairs() const { return get_aligned_Java_u4_at(1 + 1*jintSize); } LookupswitchPair pair_at(int i) const { assert(0 <= i && i < number_of_pairs(), "pair index out of bounds"); return LookupswitchPair(aligned_addr_at(1 + (1 + i)*2*jintSize)); @@ -166,9 +166,9 @@ class Bytecode_tableswitch: public Bytecode { void verify() const PRODUCT_RETURN; // Attributes - int default_offset() const { return get_Java_u4_at(aligned_offset(1 + 0*jintSize)); } - int low_key() const { return get_Java_u4_at(aligned_offset(1 + 1*jintSize)); } - int high_key() const { return get_Java_u4_at(aligned_offset(1 + 2*jintSize)); } + int default_offset() const { return get_aligned_Java_u4_at(1 + 0*jintSize); } + int low_key() const { return get_aligned_Java_u4_at(1 + 1*jintSize); } + int high_key() const { return get_aligned_Java_u4_at(1 + 2*jintSize); } int dest_offset_at(int i) const; int length() { return high_key()-low_key()+1; } }; diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index 745fb5199ec..cca40f1aeb2 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -554,7 +554,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::gather_metadata(Handle target, Handle _constants = buffer.consts(); initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, false, CHECK_OK); if (result != JVMCIEnv::ok) { return result; } @@ -587,7 +587,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand _constants = buffer.consts(); initialize_fields(target(), JNIHandles::resolve(compiled_code_obj), CHECK_OK); - JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, CHECK_OK); + JVMCIEnv::CodeInstallResult result = initialize_buffer(buffer, true, CHECK_OK); if (result != JVMCIEnv::ok) { return result; } @@ -726,7 +726,7 @@ int CodeInstaller::estimate_stubs_size(TRAPS) { } // perform data and call relocation on the CodeBuffer -JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, TRAPS) { +JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS) { HandleMark hm; objArrayHandle sites = this->sites(); int locs_buffer_size = sites->length() * (relocInfo::length_limit + sizeof(relocInfo)); @@ -738,7 +738,7 @@ JVMCIEnv::CodeInstallResult CodeInstaller::initialize_buffer(CodeBuffer& buffer, int stubs_size = estimate_stubs_size(CHECK_OK); int total_size = round_to(_code_size, buffer.insts()->alignment()) + round_to(_constants_size, buffer.consts()->alignment()) + round_to(stubs_size, buffer.stubs()->alignment()); - if (total_size > JVMCINMethodSizeLimit) { + if (check_size && total_size > JVMCINMethodSizeLimit) { return JVMCIEnv::code_too_large; } @@ -1258,6 +1258,7 @@ void CodeInstaller::site_Mark(CodeBuffer& buffer, jint pc_offset, Handle site, T case HEAP_TOP_ADDRESS: case HEAP_END_ADDRESS: case NARROW_KLASS_BASE_ADDRESS: + case NARROW_OOP_BASE_ADDRESS: case CRC_TABLE_ADDRESS: case LOG_OF_HEAP_REGION_GRAIN_BYTES: case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED: diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index 775a8c19f40..a700174de1d 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -133,9 +133,10 @@ private: HEAP_TOP_ADDRESS = 17, HEAP_END_ADDRESS = 18, NARROW_KLASS_BASE_ADDRESS = 19, - CRC_TABLE_ADDRESS = 20, - LOG_OF_HEAP_REGION_GRAIN_BYTES = 21, - INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 22, + NARROW_OOP_BASE_ADDRESS = 20, + CRC_TABLE_ADDRESS = 21, + LOG_OF_HEAP_REGION_GRAIN_BYTES = 22, + INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = 23, INVOKE_INVALID = -1 }; @@ -227,7 +228,7 @@ protected: int estimate_stubs_size(TRAPS); // perform data and call relocation on the CodeBuffer - JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, TRAPS); + JVMCIEnv::CodeInstallResult initialize_buffer(CodeBuffer& buffer, bool check_size, TRAPS); void assumption_NoFinalizableSubclass(Handle assumption); void assumption_ConcreteSubtype(Handle assumption); diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index f7eb56ff404..2fe6b45b79e 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -591,12 +591,16 @@ C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv *, jobject, job return method->is_ignored_by_security_stack_walk(); C2V_END -C2V_VMENTRY(jboolean, canInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) +C2V_VMENTRY(jboolean, isCompilable,(JNIEnv *, jobject, jobject jvmci_method)) methodHandle method = CompilerToVM::asMethod(jvmci_method); - // In hosted mode ignore the not_compilable flags since they are never set by + // Ignore the not_compilable flags in hosted mode since they are never set by // the JVMCI compiler. - bool is_compilable = UseJVMCICompiler ? !method->is_not_compilable(CompLevel_full_optimization) : true; - return is_compilable && !CompilerOracle::should_not_inline(method) && !method->dont_inline(); + return UseJVMCICompiler || !method->is_not_compilable(CompLevel_full_optimization); +C2V_END + +C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv *, jobject, jobject jvmci_method)) + methodHandle method = CompilerToVM::asMethod(jvmci_method); + return CompilerOracle::should_not_inline(method) || method->dont_inline(); C2V_END C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv *, jobject, jobject jvmci_method)) @@ -1591,7 +1595,8 @@ JNINativeMethod CompilerToVM::methods[] = { {CC "getStackTraceElement", CC "(" HS_RESOLVED_METHOD "I)" STACK_TRACE_ELEMENT, FN_PTR(getStackTraceElement)}, {CC "methodIsIgnoredBySecurityStackWalk", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(methodIsIgnoredBySecurityStackWalk)}, {CC "doNotInlineOrCompile", CC "(" HS_RESOLVED_METHOD ")V", FN_PTR(doNotInlineOrCompile)}, - {CC "canInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(canInlineMethod)}, + {CC "isCompilable", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(isCompilable)}, + {CC "hasNeverInlineDirective", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(hasNeverInlineDirective)}, {CC "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)}, {CC "lookupType", CC "(" STRING CLASS "Z)" HS_RESOLVED_KLASS, FN_PTR(lookupType)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)}, diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 2dad27fdfd9..a01651f55aa 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -429,6 +429,7 @@ declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_OOP_BASE_ADDRESS) \ declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ declare_constant(CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES) \ declare_constant(CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED) \ @@ -534,7 +535,6 @@ \ declare_constant(markOopDesc::no_hash) \ \ - declare_constant(Method::_jfr_towrite) \ declare_constant(Method::_caller_sensitive) \ declare_constant(Method::_force_inline) \ declare_constant(Method::_dont_inline) \ diff --git a/hotspot/src/share/vm/logging/logConfiguration.cpp b/hotspot/src/share/vm/logging/logConfiguration.cpp index b8a5932ba0e..9b77b220e70 100644 --- a/hotspot/src/share/vm/logging/logConfiguration.cpp +++ b/hotspot/src/share/vm/logging/logConfiguration.cpp @@ -478,7 +478,7 @@ void LogConfiguration::describe(outputStream* out) { void LogConfiguration::print_command_line_help(FILE* out) { jio_fprintf(out, "-Xlog Usage: -Xlog[:[what][:[output][:[decorators][:output-options]]]]\n" - "\t where 'what' is a combination of tags and levels on the form tag1[+tag2...][*][=level][,...]\n" + "\t where 'what' is a combination of tags and levels of the form tag1[+tag2...][*][=level][,...]\n" "\t Unless wildcard (*) is specified, only log messages tagged with exactly the tags specified will be matched.\n\n"); jio_fprintf(out, "Available log levels:\n"); @@ -514,6 +514,14 @@ void LogConfiguration::print_command_line_help(FILE* out) { " -Xlog:gc\n" "\t Log messages tagged with 'gc' tag using 'info' level to stdout, with default decorations.\n\n" + " -Xlog:gc,safepoint\n" + "\t Log messages tagged either with 'gc' or 'safepoint' tags, both using 'info' level, to stdout, with default decorations.\n" + "\t (Messages tagged with both 'gc' and 'safepoint' will not be logged.)\n\n" + + " -Xlog:gc+ref=debug\n" + "\t Log messages tagged with both 'gc' and 'ref' tags, using 'debug' level, to stdout, with default decorations.\n" + "\t (Messages tagged only with one of the two tags will not be logged.)\n\n" + " -Xlog:gc=debug:file=gc.txt:none\n" "\t Log messages tagged with 'gc' tag using 'debug' level to file 'gc.txt' with no decorations.\n\n" diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 61d6fa37b41..446517fd426 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -145,10 +145,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc, GrowableArray StringTable::serialize(soc, string_space, space_size); soc->do_tag(--tag); - // Dump/restore the misc information for system dictionary - SystemDictionaryShared::serialize(soc); - soc->do_tag(--tag); - soc->do_tag(666); } diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 5b2180f945c..41f5fd143a8 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2139,8 +2139,6 @@ void InstanceKlass::release_C_heap_structures(InstanceKlass* ik) { } void InstanceKlass::release_C_heap_structures() { - assert(!this->is_shared(), "should not be called for a shared class"); - // Can't release the constant pool here because the constant pool can be // deallocated separately from the InstanceKlass for default methods and // redefine classes. @@ -2191,7 +2189,7 @@ void InstanceKlass::release_C_heap_structures() { } // deallocate the cached class file - if (_cached_class_file != NULL) { + if (_cached_class_file != NULL && !MetaspaceShared::is_in_shared_space(_cached_class_file)) { os::free(_cached_class_file); _cached_class_file = NULL; } diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 4e3dcf03bd8..f37278edd13 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -85,7 +85,6 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags) { set_constMethod(xconst); set_access_flags(access_flags); set_intrinsic_id(vmIntrinsics::_none); - set_jfr_towrite(false); set_force_inline(false); set_hidden(false); set_dont_inline(false); diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 1c6e72df0fc..ebd5f0feef2 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -75,18 +75,19 @@ class Method : public Metadata { // Flags enum Flags { - _jfr_towrite = 1 << 0, - _caller_sensitive = 1 << 1, - _force_inline = 1 << 2, - _dont_inline = 1 << 3, - _hidden = 1 << 4, - _has_injected_profile = 1 << 5, - _running_emcp = 1 << 6, - _intrinsic_candidate = 1 << 7, - _reserved_stack_access = 1 << 8 + _caller_sensitive = 1 << 0, + _force_inline = 1 << 1, + _dont_inline = 1 << 2, + _hidden = 1 << 3, + _has_injected_profile = 1 << 4, + _running_emcp = 1 << 5, + _intrinsic_candidate = 1 << 6, + _reserved_stack_access = 1 << 7 }; mutable u2 _flags; + TRACE_DEFINE_FLAG; + #ifndef PRODUCT int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging) #endif @@ -833,13 +834,6 @@ class Method : public Metadata { void init_intrinsic_id(); // updates from _none if a match static vmSymbols::SID klass_id_for_intrinsics(const Klass* holder); - bool jfr_towrite() const { - return (_flags & _jfr_towrite) != 0; - } - void set_jfr_towrite(bool x) const { - _flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite); - } - bool caller_sensitive() { return (_flags & _caller_sensitive) != 0; } @@ -890,6 +884,8 @@ class Method : public Metadata { _flags = x ? (_flags | _reserved_stack_access) : (_flags & ~_reserved_stack_access); } + TRACE_DEFINE_FLAG_ACCESSOR; + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } diff --git a/hotspot/src/share/vm/oops/methodData.cpp b/hotspot/src/share/vm/oops/methodData.cpp index 85f7c9b6098..a99000aabcf 100644 --- a/hotspot/src/share/vm/oops/methodData.cpp +++ b/hotspot/src/share/vm/oops/methodData.cpp @@ -717,9 +717,9 @@ MethodData* MethodData::allocate(ClassLoaderData* loader_data, const methodHandl } int MethodData::bytecode_cell_count(Bytecodes::Code code) { -#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) - return no_profile_data; -#else + if (is_client_compilation_mode_vm()) { + return no_profile_data; + } switch (code) { case Bytecodes::_checkcast: case Bytecodes::_instanceof: @@ -778,7 +778,6 @@ int MethodData::bytecode_cell_count(Bytecodes::Code code) { return variable_cell_count; } return no_profile_data; -#endif } // Compute the size of the profiling information corresponding to @@ -840,7 +839,9 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) { case Bytecodes::_ifnonnull: case Bytecodes::_invokestatic: #ifdef COMPILER2 - return UseTypeSpeculation; + if (is_server_compilation_mode_vm()) { + return UseTypeSpeculation; + } #endif default: return false; @@ -942,9 +943,9 @@ int MethodData::compute_allocation_size_in_words(const methodHandle& method) { // the segment in bytes. int MethodData::initialize_data(BytecodeStream* stream, int data_index) { -#if defined(COMPILER1) && !(defined(COMPILER2) || INCLUDE_JVMCI) - return 0; -#else + if (is_client_compilation_mode_vm()) { + return 0; + } int cell_count = -1; int tag = DataLayout::no_tag; DataLayout* data_layout = data_layout_at(data_index); @@ -1061,7 +1062,6 @@ int MethodData::initialize_data(BytecodeStream* stream, assert(!bytecode_has_profile(c), "agree w/ !BHP"); return 0; } -#endif } // Get the data at an arbitrary (sort of) data index. diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index a85b64e8801..627fba527e2 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -2183,7 +2183,7 @@ private: uint _nof_overflow_traps; // trap count, excluding _trap_hist union { intptr_t _align; - u1 _array[_trap_hist_limit]; + u1 _array[JVMCI_ONLY(2 *) _trap_hist_limit]; } _trap_hist; // Support for interprocedural escape analysis, from Thomas Kotzmann. diff --git a/hotspot/src/share/vm/opto/cfgnode.cpp b/hotspot/src/share/vm/opto/cfgnode.cpp index 47606b6a599..de85b1cb155 100644 --- a/hotspot/src/share/vm/opto/cfgnode.cpp +++ b/hotspot/src/share/vm/opto/cfgnode.cpp @@ -2097,6 +2097,7 @@ const RegMask &PhiNode::out_RegMask() const { uint ideal_reg = _type->ideal_reg(); assert( ideal_reg != Node::NotAMachineReg, "invalid type at Phi" ); if( ideal_reg == 0 ) return RegMask::Empty; + assert(ideal_reg != Op_RegFlags, "flags register is not spillable"); return *(Compile::current()->matcher()->idealreg2spillmask[ideal_reg]); } diff --git a/hotspot/src/share/vm/opto/coalesce.cpp b/hotspot/src/share/vm/opto/coalesce.cpp index 1e8af4e27ee..fb45d92df42 100644 --- a/hotspot/src/share/vm/opto/coalesce.cpp +++ b/hotspot/src/share/vm/opto/coalesce.cpp @@ -292,7 +292,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { // Copy any flags as well _phc.clone_projs(pred, pred->end_idx(), m, copy, _phc._lrg_map); } else { - const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()]; + int ireg = m->ideal_reg(); + if (ireg == 0 || ireg == Op_RegFlags) { + assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s", + m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::PhiInput)); + C->record_method_not_compilable("attempted to spill a non-spillable item"); + return; + } + const RegMask *rm = C->matcher()->idealreg2spillmask[ireg]; copy = new MachSpillCopyNode(MachSpillCopyNode::PhiInput, m, *rm, *rm); // Find a good place to insert. Kinda tricky, use a subroutine insert_copy_with_overlap(pred,copy,phi_name,src_name); @@ -326,7 +333,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { b->insert_node(copy, l++); l += _phc.clone_projs(b, l, m, copy, _phc._lrg_map); } else { - const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()]; + int ireg = m->ideal_reg(); + if (ireg == 0 || ireg == Op_RegFlags) { + assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s", + m->_idx, m->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::TwoAddress)); + C->record_method_not_compilable("attempted to spill a non-spillable item"); + return; + } + const RegMask *rm = C->matcher()->idealreg2spillmask[ireg]; copy = new MachSpillCopyNode(MachSpillCopyNode::TwoAddress, m, *rm, *rm); // Insert the copy in the basic block, just before us b->insert_node(copy, l++); @@ -373,7 +387,14 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { if( k < b->_num_succs ) continue; // Live out; do not pre-split // Split the lrg at this use - const RegMask *rm = C->matcher()->idealreg2spillmask[inp->ideal_reg()]; + int ireg = inp->ideal_reg(); + if (ireg == 0 || ireg == Op_RegFlags) { + assert(false, "attempted to spill a non-spillable item: %d: %s, ireg = %d, spill_type: %s", + inp->_idx, inp->Name(), ireg, MachSpillCopyNode::spill_type(MachSpillCopyNode::DebugUse)); + C->record_method_not_compilable("attempted to spill a non-spillable item"); + return; + } + const RegMask *rm = C->matcher()->idealreg2spillmask[ireg]; Node* copy = new MachSpillCopyNode(MachSpillCopyNode::DebugUse, inp, *rm, *rm); // Insert the copy in the use-def chain n->set_req(inpidx, copy ); diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 77e20b264cb..4c84b0339ec 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -971,7 +971,7 @@ Compile::Compile( ciEnv* ci_env, _java_calls(0), _inner_loops(0), #ifndef PRODUCT - _trace_opto_output(TraceOptoOutput), + _trace_opto_output(directive->TraceOptoOutputOption), _in_dump_cnt(0), _printer(NULL), #endif diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index c879137d882..1c328b7bb75 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3152,19 +3152,6 @@ Node* GraphKit::insert_mem_bar_volatile(int opcode, int alias_idx, Node* precede return membar; } -void GraphKit::insert_store_load_for_barrier() { - Node* mem = reset_memory(); - MemBarNode* mb = MemBarNode::make(C, Op_MemBarVolatile, Compile::AliasIdxBot); - mb->init_req(TypeFunc::Control, control()); - mb->init_req(TypeFunc::Memory, mem); - Node* membar = _gvn.transform(mb); - set_control(_gvn.transform(new ProjNode(membar, TypeFunc::Control))); - Node* newmem = _gvn.transform(new ProjNode(membar, TypeFunc::Memory)); - set_all_memory(mem); - set_memory(newmem, Compile::AliasIdxRaw); -} - - //------------------------------shared_lock------------------------------------ // Emit locking code. FastLockNode* GraphKit::shared_lock(Node* obj) { @@ -3854,7 +3841,7 @@ void GraphKit::write_barrier_post(Node* oop_store, BasicType bt = T_BYTE; if (UseConcMarkSweepGC && UseCondCardMark) { - insert_store_load_for_barrier(); + insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier __ sync_kit(this); } @@ -4294,7 +4281,8 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, __ if_then(card_val, BoolTest::ne, young_card); { sync_kit(ideal); - insert_store_load_for_barrier(); + // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier. + insert_mem_bar(Op_MemBarVolatile, oop_store); __ sync_kit(this); Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); @@ -4348,20 +4336,16 @@ Node* GraphKit::load_String_value(Node* ctrl, Node* str) { } Node* GraphKit::load_String_coder(Node* ctrl, Node* str) { - if (java_lang_String::has_coder_field()) { - if (!CompactStrings) { - return intcon(java_lang_String::CODER_UTF16); - } - int coder_offset = java_lang_String::coder_offset_in_bytes(); - const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), - false, NULL, 0); - const TypePtr* coder_field_type = string_type->add_offset(coder_offset); - int coder_field_idx = C->get_alias_index(coder_field_type); - return make_load(ctrl, basic_plus_adr(str, str, coder_offset), - TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered); - } else { - return intcon(0); // false + if (!CompactStrings) { + return intcon(java_lang_String::CODER_UTF16); } + int coder_offset = java_lang_String::coder_offset_in_bytes(); + const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), + false, NULL, 0); + const TypePtr* coder_field_type = string_type->add_offset(coder_offset); + int coder_field_idx = C->get_alias_index(coder_field_type); + return make_load(ctrl, basic_plus_adr(str, str, coder_offset), + TypeInt::BYTE, T_BYTE, coder_field_idx, MemNode::unordered); } void GraphKit::store_String_value(Node* ctrl, Node* str, Node* value) { diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 6d60539b527..cbae7ce3761 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -837,7 +837,6 @@ class GraphKit : public Phase { int next_monitor(); Node* insert_mem_bar(int opcode, Node* precedent = NULL); Node* insert_mem_bar_volatile(int opcode, int alias_idx, Node* precedent = NULL); - void insert_store_load_for_barrier(); // Optional 'precedent' is appended as an extra edge, to force ordering. FastLockNode* shared_lock(Node* obj); void shared_unlock(Node* box, Node* obj); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index c298e318ab5..5d837d6ecb0 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -6335,7 +6335,7 @@ bool LibraryCallKit::inline_counterMode_AESCrypt(vmIntrinsics::ID id) { //------------------------------get_key_start_from_aescrypt_object----------------------- Node * LibraryCallKit::get_key_start_from_aescrypt_object(Node *aescrypt_object) { -#ifdef PPC64 +#if defined(PPC64) || defined(S390) // MixColumns for decryption can be reduced by preprocessing MixColumns with round keys. // Intel's extention is based on this optimization and AESCrypt generates round keys by preprocessing MixColumns. // However, ppc64 vncipher processes MixColumns and requires the same round keys with encryption. diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index cd0839c3294..07f791d05d1 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -643,6 +643,7 @@ const RegMask &MachSafePointNode::in_RegMask( uint idx ) const { } // Values outside the domain represent debug info + assert(in(idx)->ideal_reg() != Op_RegFlags, "flags register is not spillable"); return *Compile::current()->matcher()->idealreg2spillmask[in(idx)->ideal_reg()]; } diff --git a/hotspot/src/share/vm/opto/macro.cpp b/hotspot/src/share/vm/opto/macro.cpp index 9bae43a4e28..bd0a1b75c9a 100644 --- a/hotspot/src/share/vm/opto/macro.cpp +++ b/hotspot/src/share/vm/opto/macro.cpp @@ -426,7 +426,7 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me // Generate loads from source of the arraycopy for fields of // destination needed at a deoptimization point -Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc) { +Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc) { BasicType bt = ft; const Type *type = ftype; if (ft == T_NARROWOOP) { @@ -438,8 +438,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* base = ac->in(ArrayCopyNode::Src)->in(AddPNode::Base); Node* adr = _igvn.transform(new AddPNode(base, base, MakeConX(offset))); const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset); - Node* m = ac->in(TypeFunc::Memory); - res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); + res = LoadNode::make(_igvn, ctl, mem, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); } else { if (ac->modifies(offset, offset, &_igvn, true)) { assert(ac->in(ArrayCopyNode::Dest) == alloc->result_cast(), "arraycopy destination should be allocation's result"); @@ -454,8 +453,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* base = ac->in(ArrayCopyNode::Src); Node* adr = _igvn.transform(new AddPNode(base, base, off)); const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset); - Node* m = ac->in(TypeFunc::Memory); - res = LoadNode::make(_igvn, ctl, m, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); + res = LoadNode::make(_igvn, ctl, mem, adr, adr_type, type, bt, MemNode::unordered, LoadNode::Pinned); } } if (res != NULL) { @@ -544,7 +542,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type * assert(false, "Object is not scalar replaceable if a LoadStore node accesses its field"); return NULL; } else if (val->is_ArrayCopy()) { - Node* res = make_arraycopy_load(val->as_ArrayCopy(), offset, val->in(0), ft, phi_type, alloc); + Node* res = make_arraycopy_load(val->as_ArrayCopy(), offset, val->in(0), val->in(TypeFunc::Memory), ft, phi_type, alloc); if (res == NULL) { return NULL; } @@ -657,11 +655,13 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType } } else if (mem->is_ArrayCopy()) { Node* ctl = mem->in(0); + Node* m = mem->in(TypeFunc::Memory); if (sfpt_ctl->is_Proj() && sfpt_ctl->as_Proj()->is_uncommon_trap_proj(Deoptimization::Reason_none)) { // pin the loads in the uncommon trap path ctl = sfpt_ctl; + m = sfpt_mem; } - return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, ft, ftype, alloc); + return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, m, ft, ftype, alloc); } } // Something go wrong. diff --git a/hotspot/src/share/vm/opto/macro.hpp b/hotspot/src/share/vm/opto/macro.hpp index ba8e9eac8e4..5482a1d8282 100644 --- a/hotspot/src/share/vm/opto/macro.hpp +++ b/hotspot/src/share/vm/opto/macro.hpp @@ -200,7 +200,7 @@ private: Node* old_eden_top, Node* new_eden_top, Node* length); - Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, BasicType ft, const Type *ftype, AllocateNode *alloc); + Node* make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* ctl, Node* mem, BasicType ft, const Type *ftype, AllocateNode *alloc); public: PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn), _has_locks(false) { diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 7c7ed8dd493..698b0bae068 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -85,6 +85,7 @@ Matcher::Matcher() idealreg2spillmask [Op_VecX] = NULL; idealreg2spillmask [Op_VecY] = NULL; idealreg2spillmask [Op_VecZ] = NULL; + idealreg2spillmask [Op_RegFlags] = NULL; idealreg2debugmask [Op_RegI] = NULL; idealreg2debugmask [Op_RegN] = NULL; @@ -97,6 +98,7 @@ Matcher::Matcher() idealreg2debugmask [Op_VecX] = NULL; idealreg2debugmask [Op_VecY] = NULL; idealreg2debugmask [Op_VecZ] = NULL; + idealreg2debugmask [Op_RegFlags] = NULL; idealreg2mhdebugmask[Op_RegI] = NULL; idealreg2mhdebugmask[Op_RegN] = NULL; @@ -109,6 +111,7 @@ Matcher::Matcher() idealreg2mhdebugmask[Op_VecX] = NULL; idealreg2mhdebugmask[Op_VecY] = NULL; idealreg2mhdebugmask[Op_VecZ] = NULL; + idealreg2mhdebugmask[Op_RegFlags] = NULL; debug_only(_mem_node = NULL;) // Ideal memory node consumed by mach node } diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp index 6e92398898a..5f516c5e7e2 100644 --- a/hotspot/src/share/vm/precompiled/precompiled.hpp +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp @@ -23,7 +23,7 @@ */ // Precompiled headers are turned off for Sun Studion, -// or if the user passes USE_PRECOMPILED_HEADER=0 to the makefiles. +// or if the user passes --disable-precompiled-headers to configure. #ifndef DONT_USE_PRECOMPILED_HEADER # include "asm/assembler.hpp" diff --git a/hotspot/src/share/vm/prims/jniCheck.cpp b/hotspot/src/share/vm/prims/jniCheck.cpp index ea80b5b8110..9ba9e1ad419 100644 --- a/hotspot/src/share/vm/prims/jniCheck.cpp +++ b/hotspot/src/share/vm/prims/jniCheck.cpp @@ -238,8 +238,8 @@ functionExit(JavaThread* thr) size_t live_handles = handles->get_number_of_live_handles(); if (live_handles > planned_capacity) { IN_VM( - tty->print_cr("WARNING: JNI local refs: %zu, exceeds capacity: %zu", - live_handles, planned_capacity); + tty->print_cr("WARNING: JNI local refs: " SIZE_FORMAT ", exceeds capacity: " SIZE_FORMAT, + live_handles, planned_capacity); thr->print_stack(); ) // Complain just the once, reset to current + warn threshold diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 6a1b4dda087..2955463852e 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1009,9 +1009,9 @@ JVM_END // Module support ////////////////////////////////////////////////////////////////////////////// JVM_ENTRY(void, JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version, - jstring location, jobjectArray packages)) + jstring location, const char* const* packages, jsize num_packages)) JVMWrapper("JVM_DefineModule"); - Modules::define_module(module, version, location, packages, CHECK); + Modules::define_module(module, version, location, packages, num_packages, CHECK); JVM_END JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)) @@ -1019,17 +1019,17 @@ JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)) Modules::set_bootloader_unnamed_module(module, CHECK); JVM_END -JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module)) +JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, const char* package, jobject to_module)) JVMWrapper("JVM_AddModuleExports"); Modules::add_module_exports_qualified(from_module, package, to_module, CHECK); JVM_END -JVM_ENTRY(void, JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package)) +JVM_ENTRY(void, JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, const char* package)) JVMWrapper("JVM_AddModuleExportsToAllUnnamed"); Modules::add_module_exports_to_all_unnamed(from_module, package, CHECK); JVM_END -JVM_ENTRY(void, JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package)) +JVM_ENTRY(void, JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, const char* package)) JVMWrapper("JVM_AddModuleExportsToAll"); Modules::add_module_exports(from_module, package, NULL, CHECK); JVM_END @@ -1039,16 +1039,11 @@ JVM_ENTRY (void, JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject so Modules::add_reads_module(from_module, source_module, CHECK); JVM_END -JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, jstring package)) +JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, const char* package)) JVMWrapper("JVM_AddModulePackage"); Modules::add_module_package(module, package, CHECK); JVM_END -JVM_ENTRY (jobject, JVM_GetModuleByPackageName(JNIEnv *env, jobject loader, jstring package)) - JVMWrapper("JVM_GetModuleByPackageName"); - return Modules::get_module_by_package_name(loader, package, THREAD); -JVM_END - // Reflection support ////////////////////////////////////////////////////////////////////////////// JVM_ENTRY(jstring, JVM_GetClassName(JNIEnv *env, jclass cls)) diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index c713645024e..e105c97766d 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -412,30 +412,67 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, * Module support funcions */ +/* + * Define a module with the specified packages and bind the module to the + * given class loader. + * module: module to define + * is_open: specifies if module is open (currently ignored) + * version: the module version + * location: the module location + * packages: list of packages in the module + * num_packages: number of packages in the module + */ JNIEXPORT void JNICALL JVM_DefineModule(JNIEnv *env, jobject module, jboolean is_open, jstring version, - jstring location, jobjectArray packages); + jstring location, const char* const* packages, jsize num_packages); +/* + * Set the boot loader's unnamed module. + * module: boot loader's unnamed module + */ JNIEXPORT void JNICALL JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); +/* + * Do a qualified export of a package. + * from_module: module containing the package to export + * package: name of the package to export + * to_module: module to export the package to + */ JNIEXPORT void JNICALL -JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); +JVM_AddModuleExports(JNIEnv *env, jobject from_module, const char* package, jobject to_module); +/* + * Do an export of a package to all unnamed modules. + * from_module: module containing the package to export + * package: name of the package to export to all unnamed modules + */ JNIEXPORT void JNICALL -JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package); +JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, const char* package); +/* + * Do an unqualified export of a package. + * from_module: module containing the package to export + * package: name of the package to export + */ JNIEXPORT void JNICALL -JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package); +JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, const char* package); +/* + * Add a module to the list of modules that a given module can read. + * from_module: module requesting read access + * source_module: module that from_module wants to read + */ JNIEXPORT void JNICALL JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module); +/* + * Add a package to a module. + * module: module that will contain the package + * package: package to add to the module + */ JNIEXPORT void JNICALL -JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package); - -JNIEXPORT jobject JNICALL -JVM_GetModuleByPackageName(JNIEnv* env, jobject loader, jstring package); +JVM_AddModulePackage(JNIEnv* env, jobject module, const char* package); /* * Reflection support functions diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index 0f390214eb2..7a0515c2bc4 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -1,7 +1,7 @@ defines first_mod --> no packages +// defines second_mod --> packages p2 +// +// first_mod can read second_mod +// package p2 in second_mod is exported to first_mod +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in second_mod +// Access is not allowed, even after p2 is exported to all unnamed modules. + +public class AccessExportTwice { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: first_mod + // Can read: java.base, second_mod + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_first_mod = + ModuleDescriptor.module("first_mod") + .requires("java.base") + .requires("second_mod") + .build(); + + // Define module: second_mod + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to first_mod + ModuleDescriptor descriptor_second_mod = + ModuleDescriptor.module("second_mod") + .requires("java.base") + .exports("p2", Set.of("first_mod")) + .build(); + + // Set up a ModuleFinder containing all modules for this layer + ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod); + + // Resolves "first_mod" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod")); + + // Map each module to the same class loader + Map map = new HashMap<>(); + map.put("first_mod", MySameClassLoader.loader1); + map.put("second_mod", MySameClassLoader.loader1); + + // Create Layer that contains first_mod & second_mod + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("first_mod") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("second_mod") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = MySameClassLoader.loader1.loadClass("p2.c2"); + // Use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + // First access check for p1.c1 + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, the unnamed module should not have access to public type p2.c2"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module second_mod does not export p2 to unnamed module"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #1"); + } + } + + // Export second_mod/p2 to all unnamed modules. + Module second_mod = p2_c2_class.getModule(); + jdk.internal.module.Modules.addExportsToAllUnnamed(second_mod, "p2"); + + // Second access check for p1.c1, should have same result as first + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, access should have been cached above"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module second_mod does not export p2 to unnamed module"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #2"); + } + } + } + + public static void main(String args[]) throws Throwable { + AccessExportTwice test = new AccessExportTwice(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java new file mode 100644 index 00000000000..5d1a690a740 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/AccessReadTwice.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @summary Class p1.c1 in module first_mod cannot read p2.c2 in module second_mod, + * even after a read edge is added between first_mod and second_mod. + * Ensures constant access check answers when not accessible due to readability. + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.module + * @compile p2/c2.java + * @compile p1/c1.java + * @compile p4/c4.java + * @run main/othervm AccessReadTwice + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +// +// ClassLoader1 --> defines first_mod --> packages p1, p4 +// defines second_mod --> package p2 +// +// package p2 in second_mod is exported to first_mod +// +// class p1.c1 defined in first_mod tries to access p2.c2 defined in second_mod +// Access is not allowed, even after a read edge is added between first_mod and second_mod. + +public class AccessReadTwice { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publicly defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: first_mod + // Can read: java.base + // Packages: p1, p4 + // Packages exported: none + ModuleDescriptor descriptor_first_mod = + ModuleDescriptor.module("first_mod") + .requires("java.base") + .contains(Set.of("p1", "p4")) + .build(); + + // Define module: second_mod + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to first_mod + ModuleDescriptor descriptor_second_mod = + ModuleDescriptor.module("second_mod") + .requires("java.base") + .exports("p2", Set.of("first_mod")) + .build(); + + // Set up a ModuleFinder containing all modules for this layer + ModuleFinder finder = ModuleLibrary.of(descriptor_first_mod, descriptor_second_mod); + + // Resolves "first_mod" and "second_mod" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.of(), Set.of("first_mod", "second_mod")); + + // Map each module to this class loader + Map map = new HashMap<>(); + ClassLoader loader = AccessReadTwice.class.getClassLoader(); + map.put("first_mod", loader); + map.put("second_mod", loader); + + // Create Layer that contains first_mod & second_mod + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("first_mod") == loader); + assertTrue(layer.findLoader("second_mod") == loader); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = loader.loadClass("p2.c2"); + Class p1_c1_class = loader.loadClass("p1.c1"); + Class p4_c4_class = loader.loadClass("p4.c4"); + + Module first_mod = p1_c1_class.getModule(); + Module second_mod = p2_c2_class.getModule(); + + // Export first_mod/p1 and first_mod/p4 to all unnamed modules so that + // this test can use them + jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p1"); + jdk.internal.module.Modules.addExportsToAllUnnamed(first_mod, "p4"); + + // First access check for p1.c1 + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, module first_mod should not have access to p2.c2"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #1"); + } + } + + // Add a read edge from p4/c4's module (first_mod) to second_mod + p4.c4 c4_obj = new p4.c4(); + c4_obj.addReads(second_mod); + + // Second access check for p1.c1, should have same result as first + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, access should have been cached above"); + } catch (IllegalAccessError e) { + String message = e.getMessage(); + if (!(message.contains("cannot access") && + message.contains("because module first_mod does not read module second_mod"))) { + throw new RuntimeException("Wrong message: " + message); + } else { + System.out.println("Test Succeeded at attempt #2"); + } + } + } + + public static void main(String args[]) throws Throwable { + AccessReadTwice test = new AccessReadTwice(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/p4/c4.java b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java new file mode 100644 index 00000000000..d0098674672 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p4/c4.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck/* tests. + +package p4; + +import java.lang.reflect.Module; + +public class c4 { + // Add a read edge from c4's module to given module m + public void addReads(Module m) { + c4.class.getModule().addReads(m); + } +} diff --git a/hotspot/test/runtime/modules/JVMAddModulePackage.java b/hotspot/test/runtime/modules/JVMAddModulePackage.java index 62106f8597f..3f7f2fd29a0 100644 --- a/hotspot/test/runtime/modules/JVMAddModulePackage.java +++ b/hotspot/test/runtime/modules/JVMAddModulePackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,11 +84,11 @@ public class JVMAddModulePackage { // Expected } - // Existing package, expect an IAE + // Existing package, expect an ISE try { ModuleHelper.AddModulePackage(module1, "yourpackage"); - throw new RuntimeException("Failed to get the expected IAE"); - } catch(IllegalArgumentException e) { + throw new RuntimeException("Failed to get the expected ISE"); + } catch(IllegalStateException e) { // Expected } diff --git a/hotspot/test/runtime/modules/JVMDefineModule.java b/hotspot/test/runtime/modules/JVMDefineModule.java index dd19770ee98..9e44878490d 100644 --- a/hotspot/test/runtime/modules/JVMDefineModule.java +++ b/hotspot/test/runtime/modules/JVMDefineModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,27 +127,27 @@ public class JVMDefineModule { } } - // Duplicate module name, expect an IAE - m = ModuleHelper.ModuleObject("module.name", cl, new String[] { "mypackage6" }); + // Duplicate module name, expect an ISE + m = ModuleHelper.ModuleObject("Module_A", cl, new String[] { "mypackage6" }); assertNotNull(m, "Module should not be null"); ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" }); try { ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6a" }); - throw new RuntimeException("Failed to get IAE for duplicate module"); - } catch(IllegalArgumentException e) { - if (!e.getMessage().contains("Module module.name is already defined")) { - throw new RuntimeException("Failed to get expected IAE message for duplicate module: " + e.getMessage()); + throw new RuntimeException("Failed to get ISE for duplicate module"); + } catch(IllegalStateException e) { + if (!e.getMessage().contains("Module Module_A is already defined")) { + throw new RuntimeException("Failed to get expected ISE message for duplicate module: " + e.getMessage()); } } - // Package is already defined for class loader, expect an IAE + // Package is already defined for class loader, expect an ISE m = ModuleHelper.ModuleObject("dupl.pkg.module", cl, new String[] { "mypackage6b" }); try { ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage6" }); - throw new RuntimeException("Failed to get IAE for existing package"); - } catch(IllegalArgumentException e) { - if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module already exists for class loader")) { - throw new RuntimeException("Failed to get expected IAE message for duplicate package: " + e.getMessage()); + throw new RuntimeException("Failed to get ISE for existing package"); + } catch(IllegalStateException e) { + if (!e.getMessage().contains("Package mypackage6 for module dupl.pkg.module is already in another module, Module_A, defined to the class loader")) { + throw new RuntimeException("Failed to get expected ISE message for duplicate package: " + e.getMessage()); } } diff --git a/hotspot/test/serviceability/attach/AttachSetGetFlag.java b/hotspot/test/serviceability/attach/AttachSetGetFlag.java index 3b48759cc23..2d6a28cfce3 100644 --- a/hotspot/test/serviceability/attach/AttachSetGetFlag.java +++ b/hotspot/test/serviceability/attach/AttachSetGetFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ * java.compiler * java.management * jdk.attach/sun.tools.attach - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run main AttachSetGetFlag */ diff --git a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java index c22be26f951..8b3a8d8a47d 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CodeCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+SegmentedCodeCache CodeCacheTest * @run testng/othervm -XX:-SegmentedCodeCache CodeCacheTest * @run testng/othervm -Xint -XX:+SegmentedCodeCache CodeCacheTest diff --git a/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java b/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java index e0bdd408012..11a28ec9a85 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CodelistTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java index c43dfafa56f..8d40423b5e8 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java @@ -49,7 +49,7 @@ public class CompilerDirectivesDCMDTest { public void run(CommandExecutor executor) { - if (Platform.isServer()) { + if (Platform.isServer() && !Platform.isEmulatedClient()) { filename = System.getProperty("test.src", ".") + File.separator + "control2.txt"; } else { filename = System.getProperty("test.src", ".") + File.separator + "control1.txt"; diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java index 3640bbcebbb..a1b79533a3a 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @summary Test of diagnostic command Compiler.queue * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox diff --git a/hotspot/test/serviceability/dcmd/framework/HelpTest.java b/hotspot/test/serviceability/dcmd/framework/HelpTest.java index b172db8e7ca..d88ddffce71 100644 --- a/hotspot/test/serviceability/dcmd/framework/HelpTest.java +++ b/hotspot/test/serviceability/dcmd/framework/HelpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+UsePerfData HelpTest */ public class HelpTest { diff --git a/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java b/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java index be8a4d8560d..2536b4125aa 100644 --- a/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java +++ b/hotspot/test/serviceability/dcmd/framework/InvalidCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+UsePerfData InvalidCommandTest */ public class InvalidCommandTest { diff --git a/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java b/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java index dadaf3113b2..d39f0de5263 100644 --- a/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java +++ b/hotspot/test/serviceability/dcmd/framework/VMVersionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +37,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+UsePerfData VMVersionTest */ public class VMVersionTest { diff --git a/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java b/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java index bc2f3e2eb15..a3d244cef4e 100644 --- a/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java +++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramAllTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassHistogramAllTest */ public class ClassHistogramAllTest extends ClassHistogramTest { diff --git a/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java b/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java index 5b4f017ec40..fec990e5a10 100644 --- a/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java +++ b/hotspot/test/serviceability/dcmd/gc/ClassHistogramTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassHistogramTest */ public class ClassHistogramTest { diff --git a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java index 257acea6b10..d811493c1d3 100644 --- a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java +++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng HeapDumpAllTest */ public class HeapDumpAllTest extends HeapDumpTest { diff --git a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java index 257a30f899c..60444ae358c 100644 --- a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java +++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ import jdk.test.lib.dcmd.PidJcmdExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng HeapDumpTest */ public class HeapDumpTest { diff --git a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java index 22af05f0523..f49e4165688 100644 --- a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java +++ b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.process.ProcessTools; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build FinalizationRunner * @run main RunFinalizationTest */ diff --git a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java index 44bd09a6268..267e91381a5 100644 --- a/hotspot/test/serviceability/dcmd/gc/RunGCTest.java +++ b/hotspot/test/serviceability/dcmd/gc/RunGCTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -Xlog:gc=debug:RunGC.gclog -XX:-ExplicitGCInvokesConcurrent RunGCTest */ public class RunGCTest { diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java index 373edf07857..c190353803f 100644 --- a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java +++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java @@ -41,7 +41,7 @@ import org.testng.annotations.Test; * java.compiler * java.instrument * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build SimpleJvmtiAgent * @run main ClassFileInstaller SimpleJvmtiAgent * @run testng LoadAgentDcmdTest diff --git a/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java b/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java index b931c42019e..c1ca3a35442 100644 --- a/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java +++ b/hotspot/test/serviceability/dcmd/thread/PrintConcurrentLocksTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng PrintConcurrentLocksTest */ public class PrintConcurrentLocksTest extends PrintTest { diff --git a/hotspot/test/serviceability/dcmd/thread/PrintTest.java b/hotspot/test/serviceability/dcmd/thread/PrintTest.java index 77e22e1d8c5..e4af11c3261 100644 --- a/hotspot/test/serviceability/dcmd/thread/PrintTest.java +++ b/hotspot/test/serviceability/dcmd/thread/PrintTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ import java.util.regex.Pattern; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng PrintTest */ public class PrintTest { diff --git a/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java b/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java index aee55b5cc31..7c77a2d2a82 100644 --- a/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java +++ b/hotspot/test/serviceability/dcmd/vm/ClassHierarchyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassHierarchyTest */ diff --git a/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java b/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java index d2230e33d8b..60f94069986 100644 --- a/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java +++ b/hotspot/test/serviceability/dcmd/vm/ClassLoaderStatsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng ClassLoaderStatsTest */ diff --git a/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java b/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java index ac04d02b382..72f009d75e4 100644 --- a/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java +++ b/hotspot/test/serviceability/dcmd/vm/CommandLineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis CommandLineTest */ public class CommandLineTest { diff --git a/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java b/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java index 3b4cfce1b60..4bda8a8f4c6 100644 --- a/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java +++ b/hotspot/test/serviceability/dcmd/vm/DynLibsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng DynLibsTest */ diff --git a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java index f83ab760a49..3554a696119 100644 --- a/hotspot/test/serviceability/dcmd/vm/FlagsTest.java +++ b/hotspot/test/serviceability/dcmd/vm/FlagsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import org.testng.annotations.Test; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng/othervm -Xmx129m -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+ThereShouldNotBeAnyVMOptionNamedLikeThis_Right -XX:-TieredCompilation FlagsTest */ public class FlagsTest { diff --git a/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java b/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java index 71ec4e17139..8325dc85f39 100644 --- a/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java +++ b/hotspot/test/serviceability/dcmd/vm/SystemPropertiesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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 @@ import jdk.test.lib.dcmd.JMXExecutor; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng SystemPropertiesTest */ public class SystemPropertiesTest { diff --git a/hotspot/test/serviceability/dcmd/vm/UptimeTest.java b/hotspot/test/serviceability/dcmd/vm/UptimeTest.java index a907421d5da..77ff300ee2f 100644 --- a/hotspot/test/serviceability/dcmd/vm/UptimeTest.java +++ b/hotspot/test/serviceability/dcmd/vm/UptimeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import java.text.ParseException; * @modules java.base/jdk.internal.misc * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @run testng UptimeTest */ public class UptimeTest { diff --git a/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java b/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java index 1030675d8f3..0b30a67dd52 100644 --- a/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java +++ b/hotspot/test/serviceability/jvmti/GetObjectSizeClass.java @@ -35,7 +35,7 @@ import jdk.test.lib.process.ProcessTools; * java.compiler * java.instrument * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build GetObjectSizeClassAgent * @run main ClassFileInstaller GetObjectSizeClassAgent * @run main GetObjectSizeClass diff --git a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java index e2a801aaef8..57eabb72e8a 100644 --- a/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java +++ b/hotspot/test/serviceability/jvmti/GetObjectSizeOverflow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import jdk.test.lib.process.ProcessTools; * java.compiler * java.instrument * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build GetObjectSizeOverflowAgent * @run main ClassFileInstaller GetObjectSizeOverflowAgent * @run main GetObjectSizeOverflow diff --git a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java index 4a9bb2606fe..c6a203e86bc 100644 --- a/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java +++ b/hotspot/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ * java.instrument * java.management * jdk.jartool/sun.tools.jar - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build UnresolvedClassAgent * @run main TestRedefineWithUnresolvedClass */ diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java index c3dced229db..855fbad95c6 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapProc.java @@ -21,12 +21,9 @@ * questions. */ -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; +import jdk.test.lib.process.ProcessTools; import sun.management.VMManagement; @@ -38,7 +35,7 @@ public class JMapHProfLargeHeapProc { buildLargeHeap(args); // Print our pid on stdout - System.out.println("PID[" + getProcessId() + "]"); + System.out.println("PID[" + ProcessTools.getProcessId() + "]"); // Wait for input before termination System.in.read(); @@ -50,22 +47,4 @@ public class JMapHProfLargeHeapProc { } } - public static int getProcessId() throws Exception { - - // Get the current process id using a reflection hack - RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); - Field jvm = runtime.getClass().getDeclaredField("jvm"); - - jvm.setAccessible(true); - VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); - - Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); - - pid_method.setAccessible(true); - - int pid = (Integer) pid_method.invoke(mgmt); - - return pid; - } - } diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java index d2e64f75d34..2a46621d118 100644 --- a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java +++ b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ import jdk.test.lib.process.ProcessTools; * @modules java.base/jdk.internal.misc * java.compiler * java.management/sun.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build JMapHProfLargeHeapProc * @run main JMapHProfLargeHeapTest */ @@ -90,6 +90,9 @@ public class JMapHProfLargeHeapTest { try (Scanner largeHeapScanner = new Scanner( largeHeapProc.getInputStream());) { String pidstring = null; + if (!largeHeapScanner.hasNext()) { + throw new RuntimeException ("Test failed: could not open largeHeapScanner."); + } while ((pidstring = largeHeapScanner.findInLine("PID\\[[0-9].*\\]")) == null) { Thread.sleep(500); } diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java index 88a94f66cdf..98a3d29bfa4 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java @@ -59,6 +59,8 @@ public class CompileTheWorld { OUT = os; } + boolean passed = false; + try { try { if (ManagementFactory.getCompilationMXBean() == null) { @@ -84,10 +86,10 @@ public class CompileTheWorld { PathHandler.getClassCount(), Compiler.getMethodCount(), System.currentTimeMillis() - start); + passed = true; } finally { - if (os != null) { - os.close(); - } + // might have started new threads + System.exit(passed ? 0 : 1); } } diff --git a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java index 4159c483408..75d82dd1ebd 100644 --- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java +++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java @@ -101,10 +101,12 @@ public class Utils { INITIAL_COMP_LEVEL = 1; } else { String vmName = System.getProperty("java.vm.name"); - if (Utils.endsWithIgnoreCase(vmName, " Server VM")) { + String vmInfo = System.getProperty("java.vm.info"); + boolean isEmulatedClient = (vmInfo != null) && vmInfo.contains("emulated-client"); + if (Utils.endsWithIgnoreCase(vmName, " Server VM") && !isEmulatedClient) { INITIAL_COMP_LEVEL = 4; } else if (Utils.endsWithIgnoreCase(vmName, " Client VM") - || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) { + || Utils.endsWithIgnoreCase(vmName, " Minimal VM") || isEmulatedClient) { INITIAL_COMP_LEVEL = 1; } else { throw new RuntimeException("Unknown VM: " + vmName); diff --git a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java index 43c9715a95e..5e56d66bd4a 100644 --- a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java +++ b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java @@ -50,7 +50,7 @@ public class TestMutuallyExclusivePlatformPredicates { OS("isAix", "isLinux", "isOSX", "isSolaris", "isWindows"), VM_TYPE("isClient", "isServer", "isGraal", "isMinimal", "isZero", "isEmbedded"), MODE("isInt", "isMixed", "isComp"), - IGNORED("isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild", + IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isSlowDebugBuild", "shouldSAAttach", "canPtraceAttachLinux", "canAttachOSX", "isTieredSupported"); diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java index 31f24081fa1..e24461cdac9 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesDirTest.java @@ -30,11 +30,11 @@ * java.base/jdk.internal.reflect * java.management * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassesDirTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes - * @run main ClassesDirTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver ClassesDirTest prepare + * @run driver ClassesDirTest compile classes + * @run driver ClassesDirTest check * @summary testing of CompileTheWorld :: classes in directory * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java index c2823de598c..5ffe27ba0c6 100644 --- a/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java +++ b/hotspot/test/testlibrary_tests/ctw/ClassesListTest.java @@ -30,11 +30,11 @@ * java.base/jdk.internal.reflect * java.management * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassesListTest prepare - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst - * @run main ClassesListTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver ClassesListTest prepare + * @run driver/timeout=600 ClassesListTest compile classes.lst + * @run driver ClassesListTest check * @summary testing of CompileTheWorld :: list of classes in file * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/CtwTest.java b/hotspot/test/testlibrary_tests/ctw/CtwTest.java index 06b16b631b9..eb6aedc1fbe 100644 --- a/hotspot/test/testlibrary_tests/ctw/CtwTest.java +++ b/hotspot/test/testlibrary_tests/ctw/CtwTest.java @@ -21,6 +21,7 @@ * questions. */ +import java.util.Arrays; import java.util.List; import java.util.Collections; import java.util.ArrayList; @@ -38,8 +39,20 @@ import java.nio.charset.Charset; import jdk.test.lib.JDKToolFinder; import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; public abstract class CtwTest { + private static final String LOG_FILE = "ctw.log"; + private static final String[] CTW_COMMAND = { + "-Xbootclasspath/a:.", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-Dsun.hotspot.tools.ctw.logfile=" + LOG_FILE, + "--add-exports", "java.base/jdk.internal.jimage=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED", + "--add-exports", "java.base/jdk.internal.reflect=ALL-UNNAMED", + sun.hotspot.tools.ctw.CompileTheWorld.class.getName(), + }; protected final String[] shouldContain; protected CtwTest(String[] shouldContain) { this.shouldContain = shouldContain; @@ -54,7 +67,10 @@ public abstract class CtwTest { prepare(); break; case "check": - check(args); + check(); + break; + case "compile": + compile(args); break; default: throw new Error("unregonized action -- " + args[0]); @@ -63,20 +79,27 @@ public abstract class CtwTest { protected void prepare() throws Exception { } - protected void check(String[] args) throws Exception { - if (args.length < 2) { - throw new Error("logfile isn't specified"); - } - String logfile = args[1]; - try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile), + protected void check() throws Exception { + try (BufferedReader r = Files.newBufferedReader(Paths.get(LOG_FILE), Charset.defaultCharset())) { OutputAnalyzer output = readOutput(r); - for (String test : shouldContain) { + for (String test : shouldContain) { output.shouldContain(test); } } } + protected void compile(String[] args) throws Exception { + // concat CTW_COMMAND and args w/o 0th element + String[] cmd = Arrays.copyOf(CTW_COMMAND, CTW_COMMAND.length + args.length - 1); + System.arraycopy(args, 1, cmd, CTW_COMMAND.length, args.length - 1); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, cmd); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + dump(output, "compile"); + output.shouldHaveExitValue(0); + } + private static OutputAnalyzer readOutput(BufferedReader reader) throws IOException { StringBuilder builder = new StringBuilder(); diff --git a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java index a784bda84ad..18ce6347b81 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarDirTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarDirTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,13 +30,13 @@ * java.base/jdk.internal.reflect * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main JarDirTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/* - * @run main JarDirTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver JarDirTest prepare + * @run driver JarDirTest compile jars/* + * @run driver JarDirTest check * @summary testing of CompileTheWorld :: jars in directory * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/ctw/JarsTest.java b/hotspot/test/testlibrary_tests/ctw/JarsTest.java index 16af1639854..cae3f7b7193 100644 --- a/hotspot/test/testlibrary_tests/ctw/JarsTest.java +++ b/hotspot/test/testlibrary_tests/ctw/JarsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,13 +30,13 @@ * java.base/jdk.internal.reflect * java.compiler * java.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox Foo Bar - * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main JarsTest prepare - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar - * @run main JarsTest check ctw.log + * @run driver ClassFileInstaller sun.hotspot.WhiteBox Foo Bar + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run driver JarsTest prepare + * @run driver JarsTest compile foo.jar bar.jar + * @run driver JarsTest check * @summary testing of CompileTheWorld :: jars * @author igor.ignatyev@oracle.com */ diff --git a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java index 302f77c3d31..79830375479 100644 --- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java +++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/BooleanTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ * @modules java.base/jdk.internal.misc * java.compiler * java.management/sun.management - * jdk.jvmstat/sun.jvmstat.monitor + * jdk.internal.jvmstat/sun.jvmstat.monitor * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 0fd6c10ce52..9804e10e82f 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -397,3 +397,4 @@ f85154af719f99a3b4d81b67a8b4c18a650d10f9 jdk-9+150 7e3da313b1746578da648155e37dd8526e83153d jdk-9+152 1384504d2cd0e55c5e0becaeaf40ab05cae959d6 jdk-9+153 7fa738305436d14c0926df0f04892890cacc766b jdk-9+154 +48fa77af153288b08ba794e1616a7b0685f3b67e jdk-9+155 diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java index 2060a5ac8eb..32f79d67463 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java @@ -24,32 +24,32 @@ package transform; import static jaxp.library.JAXPTestUtilities.getSystemProperty; -import static jaxp.library.JAXPTestUtilities.tryRunWithTmpPermission; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.IOException; -import java.io.StringReader; import java.io.StringWriter; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.transform.Source; import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; import org.testng.Assert; import org.testng.AssertJUnit; +import org.testng.annotations.DataProvider; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.w3c.dom.Document; @@ -67,8 +67,7 @@ import org.xml.sax.SAXNotSupportedException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; -import com.sun.org.apache.xml.internal.serialize.OutputFormat; -import com.sun.org.apache.xml.internal.serialize.XMLSerializer; +import transform.util.TransformerTestTemplate; /* * @test @@ -91,250 +90,241 @@ public class TransformerTest { private static final String NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; - private static abstract class TestTemplate { - protected void printSnippet(String title, String snippet) { - StringBuilder div = new StringBuilder(); - for (int i = 0; i < title.length(); i++) - div.append("="); - System.out.println(title + "\n" + div + "\n" + snippet + "\n"); - } - } + public static class Test6272879 extends TransformerTestTemplate { - /** - * Reads the contents of the given file into a string. - * WARNING: this method adds a final line feed even if the last line of the file doesn't contain one. - * - * @param f - * The file to read - * @return The content of the file as a string, with line terminators as \"n" - * for all platforms - * @throws IOException - * If there was an error reading - */ - private String getFileContentAsString(File f) throws IOException { - try (BufferedReader reader = new BufferedReader(new FileReader(f))) { - String line; - StringBuilder sb = new StringBuilder(); - while ((line = reader.readLine()) != null) { - sb.append(line).append("\n"); + private static String XSL_INPUT = + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + "" + LINE_SEPARATOR + + ""; + + private static String XML_INPUT = + "" + LINE_SEPARATOR + + // "" + LINE_SEPARATOR + + // "" + LINE_SEPARATOR + + // "" + LINE_SEPARATOR + + // "]>" + + // LINE_SEPARATOR + + "" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " Valeur 1" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " Valeur 2" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + ""; + + public Test6272879() { + super(XSL_INPUT, XML_INPUT); + } + + /* + * @bug 6272879 + * @summary Test for JDK-6272879 + * DomResult had truncated Strings in some places + */ + @Test + public void run() throws TransformerException, ClassNotFoundException, InstantiationException, + IllegalAccessException, ClassCastException + { + // print input + printSnippet("Stylesheet:", getXsl()); + printSnippet("Source before transformation:", getSourceXml()); + + // transform to DOM result + Transformer t = getTransformer(); + DOMResult result = new DOMResult(); + t.transform(getStreamSource(), result); + + // print output + printSnippet("Result after transformation:", prettyPrintDOMResult(result)); + + // do some assertions + Document document = (Document)result.getNode(); + NodeList nodes = document.getElementsByTagName("valeur2"); + for (int i = 0; i < nodes.getLength(); i++) { + Node node = nodes.item(i); + AssertJUnit.assertEquals("Node value mismatch", + "Valeur " + (i + 1), + node.getFirstChild().getNodeValue()); + AssertJUnit.assertEquals("Node attribute mismatch", + "Attribut " + (i + 1), + node.getAttributes().item(0).getNodeValue()); } - return sb.toString(); } } - private class XMLReaderFor6305029 implements XMLReader { - private boolean namespaces = true; - private boolean namespacePrefixes = false; - private EntityResolver resolver; - private DTDHandler dtdHandler; - private ContentHandler contentHandler; - private ErrorHandler errorHandler; + public static class Test6305029 extends TransformerTestTemplate { - public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException { - if (name.equals(NAMESPACES)) { - return namespaces; - } else if (name.equals(NAMESPACE_PREFIXES)) { - return namespacePrefixes; - } else { - throw new SAXNotRecognizedException(); + private static String XML_INPUT = + "" + ""; + + // custom XMLReader representing XML_INPUT + private class MyXMLReader implements XMLReader { + private boolean namespaces = true; + private boolean namespacePrefixes = false; + private EntityResolver resolver; + private DTDHandler dtdHandler; + private ContentHandler contentHandler; + private ErrorHandler errorHandler; + + public boolean getFeature(final String name) throws SAXNotRecognizedException, SAXNotSupportedException { + if (name.equals(NAMESPACES)) { + return namespaces; + } else if (name.equals(NAMESPACE_PREFIXES)) { + return namespacePrefixes; + } else { + throw new SAXNotRecognizedException(); + } + } + + public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { + if (name.equals(NAMESPACES)) { + namespaces = value; + } else if (name.equals(NAMESPACE_PREFIXES)) { + namespacePrefixes = value; + } else { + throw new SAXNotRecognizedException(); + } + } + + public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException { + return null; + } + + public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException { + } + + public void setEntityResolver(final EntityResolver theResolver) { + this.resolver = theResolver; + } + + public EntityResolver getEntityResolver() { + return resolver; + } + + public void setDTDHandler(final DTDHandler theHandler) { + dtdHandler = theHandler; + } + + public DTDHandler getDTDHandler() { + return dtdHandler; + } + + public void setContentHandler(final ContentHandler handler) { + contentHandler = handler; + } + + public ContentHandler getContentHandler() { + return contentHandler; + } + + public void setErrorHandler(final ErrorHandler handler) { + errorHandler = handler; + } + + public ErrorHandler getErrorHandler() { + return errorHandler; + } + + public void parse(final InputSource input) throws IOException, SAXException { + parse(); + } + + public void parse(final String systemId) throws IOException, SAXException { + parse(); + } + + private void parse() throws SAXException { + contentHandler.startDocument(); + contentHandler.startPrefixMapping("prefix", "namespaceUri"); + + AttributesImpl atts = new AttributesImpl(); + if (namespacePrefixes) { + atts.addAttribute("", "xmlns:prefix", "xmlns:prefix", "CDATA", "namespaceUri"); + } + + contentHandler.startElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "", atts); + contentHandler.endElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : ""); + contentHandler.endPrefixMapping("prefix"); + contentHandler.endDocument(); } } - public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { - if (name.equals(NAMESPACES)) { - namespaces = value; - } else if (name.equals(NAMESPACE_PREFIXES)) { - namespacePrefixes = value; - } else { - throw new SAXNotRecognizedException(); - } + public Test6305029() { + super(null, XML_INPUT); } - public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException { - return null; - } + /* + * @bug 6305029 + * @summary Test for JDK-6305029 + * Test identity transformation + */ + @Test + public void run() throws TransformerFactoryConfigurationError, TransformerException { + // get Identity transformer + Transformer t = getTransformer(); - public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException { - } + // test SAXSource from custom XMLReader + SAXSource saxSource = new SAXSource(new MyXMLReader(), new InputSource()); + StringWriter resultWriter = new StringWriter(); + t.transform(saxSource, new StreamResult(resultWriter)); + String resultString = resultWriter.toString(); + printSnippet("Result after transformation from custom SAXSource:", resultString); + AssertJUnit.assertEquals("Identity transform of SAXSource", getSourceXml(), resultString); - public void setEntityResolver(final EntityResolver theResolver) { - this.resolver = theResolver; - } - - public EntityResolver getEntityResolver() { - return resolver; - } - - public void setDTDHandler(final DTDHandler theHandler) { - dtdHandler = theHandler; - } - - public DTDHandler getDTDHandler() { - return dtdHandler; - } - - public void setContentHandler(final ContentHandler handler) { - contentHandler = handler; - } - - public ContentHandler getContentHandler() { - return contentHandler; - } - - public void setErrorHandler(final ErrorHandler handler) { - errorHandler = handler; - } - - public ErrorHandler getErrorHandler() { - return errorHandler; - } - - public void parse(final InputSource input) throws IOException, SAXException { - parse(); - } - - public void parse(final String systemId) throws IOException, SAXException { - parse(); - } - - private void parse() throws SAXException { - contentHandler.startDocument(); - contentHandler.startPrefixMapping("prefix", "namespaceUri"); - - AttributesImpl atts = new AttributesImpl(); - if (namespacePrefixes) { - atts.addAttribute("", "xmlns:prefix", "xmlns:prefix", "CDATA", "namespaceUri"); - } - - contentHandler.startElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : "", atts); - contentHandler.endElement("namespaceUri", "localName", namespacePrefixes ? "prefix:localName" : ""); - contentHandler.endPrefixMapping("prefix"); - contentHandler.endDocument(); + // test StreamSource + printSnippet("Source before transformation of StreamSource:", getSourceXml()); + resultWriter = new StringWriter(); + t.transform(getStreamSource(), new StreamResult(resultWriter)); + resultString = resultWriter.toString(); + printSnippet("Result after transformation of StreamSource:", resultString); + AssertJUnit.assertEquals("Identity transform of StreamSource", getSourceXml(), resultString); } } - /* - * @bug 6272879 - * @summary Test for JDK-6272879 - */ - @Test - public final void testBug6272879() throws Exception { - final String xsl = - "" + LINE_SEPARATOR + - "" + LINE_SEPARATOR + - "" + LINE_SEPARATOR + - "" + LINE_SEPARATOR + - "" + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - "" + LINE_SEPARATOR + - "" + LINE_SEPARATOR + - ""; + public static class Test6505031 extends TransformerTestTemplate { - final String sourceXml = - "" + LINE_SEPARATOR + - // "" + LINE_SEPARATOR + - // "" + LINE_SEPARATOR + - // "" + LINE_SEPARATOR + - // "]>" + - // LINE_SEPARATOR + - "" + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " Valeur 1" + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - " Valeur 2" + LINE_SEPARATOR + - " " + LINE_SEPARATOR + - ""; + public Test6505031() throws IOException { + super(); + setXsl(fromInputStream(getClass().getResourceAsStream("transform.xsl"))); + setSourceXml(fromInputStream(getClass().getResourceAsStream("template.xml"))); + } - System.out.println("Stylesheet:"); - System.out.println("============================="); - System.out.println(xsl); - System.out.println(); - - System.out.println("Source before transformation:"); - System.out.println("============================="); - System.out.println(sourceXml); - System.out.println(); - - // transform to DOM result - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer t = tf.newTransformer(new StreamSource(new ByteArrayInputStream(xsl.getBytes()))); - DOMResult result = new DOMResult(); - t.transform(new StreamSource(new ByteArrayInputStream(sourceXml.getBytes())), result); - Document document = (Document)result.getNode(); - - System.out.println("Result after transformation:"); - System.out.println("============================"); - tryRunWithTmpPermission(() -> { - OutputFormat format = new OutputFormat(); - format.setIndenting(true); - new XMLSerializer(System.out, format).serialize(document); - }, new RuntimePermission("accessClassInPackage.com.sun.org.apache.xml.internal.serialize")); - System.out.println(); - - System.out.println("Node content for element valeur2:"); - System.out.println("================================="); - NodeList nodes = document.getElementsByTagName("valeur2"); - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - System.out.println(" Node value: " + node.getFirstChild().getNodeValue()); - System.out.println(" Node attribute: " + node.getAttributes().item(0).getNodeValue()); - - AssertJUnit.assertEquals("Node value mismatch", "Valeur " + (i + 1), node.getFirstChild().getNodeValue()); - AssertJUnit.assertEquals("Node attribute mismatch", "Attribut " + (i + 1), node.getAttributes().item(0).getNodeValue()); + /* + * @bug 6505031 + * @summary Test transformer parses keys and their values coming from different xml documents. + */ + @Test + public void run() throws TransformerFactoryConfigurationError, TransformerException { + Transformer t = getTransformer(); + t.setParameter("config", getClass().getResource("config.xml").toString()); + t.setParameter("mapsFile", getClass().getResource("maps.xml").toString()); + StringWriter resultWriter = new StringWriter(); + t.transform(getStreamSource(), new StreamResult(resultWriter)); + String resultString = resultWriter.toString(); + Assert.assertTrue(resultString.contains("map1key1value") && resultString.contains("map2key1value")); } } - /* - * @bug 6305029 - * @summary Test for JDK-6305029 - */ - @Test - public final void testBug6305029() throws TransformerException { - final String XML_DOCUMENT = "" + ""; + public static class Test8169631 extends TransformerTestTemplate { - // test SAXSource - SAXSource saxSource = new SAXSource(new XMLReaderFor6305029(), new InputSource()); - StringWriter resultWriter = new StringWriter(); - TransformerFactory tf = TransformerFactory.newInstance(); - tf.newTransformer().transform(saxSource, new StreamResult(resultWriter)); - AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, resultWriter.toString()); - - // test StreamSource - StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT)); - resultWriter = new StringWriter(); - tf.newTransformer().transform(streamSource, new StreamResult(resultWriter)); - AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, resultWriter.toString()); - } - - /* - * @bug 6505031 - * @summary Test transformer parses keys and their values coming from different xml documents. - */ - @Test - public final void testBug6505031() throws TransformerException { - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer t = tf.newTransformer(new StreamSource(getClass().getResource("transform.xsl").toString())); - t.setParameter("config", getClass().getResource("config.xml").toString()); - t.setParameter("mapsFile", getClass().getResource("maps.xml").toString()); - StringWriter sw = new StringWriter(); - t.transform(new StreamSource(getClass().getResource("template.xml").toString()), new StreamResult(sw)); - String s = sw.toString(); - Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value")); - } - - private static class Test8169631 extends TestTemplate { - private final static String xsl = + private static String XSL_INPUT = "" + LINE_SEPARATOR + "" + LINE_SEPARATOR + " " + LINE_SEPARATOR + @@ -345,7 +335,7 @@ public class TransformerTest { " " + LINE_SEPARATOR + "" + LINE_SEPARATOR; - private final static String sourceXml = + private static String XML_INPUT = "" + LINE_SEPARATOR + "" + LINE_SEPARATOR + " 1" + LINE_SEPARATOR + @@ -353,6 +343,10 @@ public class TransformerTest { " 3" + LINE_SEPARATOR + "" + LINE_SEPARATOR; + public Test8169631() { + super(XSL_INPUT, XML_INPUT); + } + /** * Utility method to print out transformation result and check values. * @@ -380,103 +374,104 @@ public class TransformerTest { type + " should have count of "+ attribCount + " attributes."); } - public void run() throws IOException, TransformerException, - SAXException, ParserConfigurationException + @DataProvider(name = "testdata8169631") + public Object[][] testData() + throws TransformerConfigurationException, SAXException, IOException, + ParserConfigurationException, XMLStreamException { - printSnippet("Source:", sourceXml); + // get Transformers + TransformerFactory tf = TransformerFactory.newInstance(); + Transformer t = getTransformer(tf); + Transformer tFromTemplates = getTemplates(tf).newTransformer(); - printSnippet("Stylesheet:", xsl); - - // create default transformer (namespace aware) - TransformerFactory tf1 = TransformerFactory.newInstance(); - ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes()); - Transformer t1 = tf1.newTransformer(new StreamSource(bais)); - - // test transformation from stream source with namespace support - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - bais = new ByteArrayInputStream(sourceXml.getBytes()); - t1.transform(new StreamSource(bais), new StreamResult(baos)); - verifyResult("StreamSource with namespace support", baos.toString(), 0, 1); - - // test transformation from DOM source with namespace support - bais.reset(); - baos.reset(); + // get DOMSource objects DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DOMSource domSourceWithoutNS = getDOMSource(dbf); dbf.setNamespaceAware(true); - Document doc = dbf.newDocumentBuilder().parse(new InputSource(bais)); - t1.transform(new DOMSource(doc), new StreamResult(baos)); - verifyResult("DOMSource with namespace support", baos.toString(), 0, 1); + DOMSource domSourceWithNS = getDOMSource(dbf); - // test transformation from DOM source without namespace support - bais.reset(); - baos.reset(); - dbf.setNamespaceAware(false); - doc = dbf.newDocumentBuilder().parse(new InputSource(bais)); - t1.transform(new DOMSource(doc), new StreamResult(baos)); - verifyResult("DOMSource without namespace support", baos.toString(), 3, 3); - - // test transformation from SAX source with namespace support - bais.reset(); - baos.reset(); + // get SAXSource objects SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXSource saxSourceWithoutNS = getSAXSource(spf); spf.setNamespaceAware(true); - XMLReader xmlr = spf.newSAXParser().getXMLReader(); - SAXSource saxS = new SAXSource(xmlr, new InputSource(bais)); - t1.transform(saxS, new StreamResult(baos)); - verifyResult("SAXSource with namespace support", baos.toString(), 0, 1); + SAXSource saxSourceWithNS = getSAXSource(spf); - // test transformation from SAX source without namespace support - bais.reset(); - baos.reset(); - spf.setNamespaceAware(false); - xmlr = spf.newSAXParser().getXMLReader(); - saxS = new SAXSource(xmlr, new InputSource(bais)); - t1.transform(saxS, new StreamResult(baos)); - verifyResult("SAXSource without namespace support", baos.toString(), 3, 3); + // get StAXSource objects + XMLInputFactory xif = XMLInputFactory.newInstance(); + StAXSource staxSourceWithNS = getStAXSource(xif); + + // print XML/XSL snippets to ease understanding of result + printSnippet("Source:", getSourceXml()); + printSnippet("Stylesheet:", getXsl()); + + return new Object[][] { + // test StreamSource input with all transformers + // namespace awareness is set by transformer + {t, getStreamSource(), "StreamSource with namespace support", 0, 1}, + {tFromTemplates, getStreamSource(), "StreamSource with namespace support using templates", 0, 1}, + // now test DOMSource, SAXSource and StAXSource + // with rotating use of created transformers + // namespace awareness is set by source objects + {t, domSourceWithNS, "DOMSource with namespace support", 0, 1}, + {t, domSourceWithoutNS, "DOMSource without namespace support", 3, 3}, + {tFromTemplates, saxSourceWithNS, "SAXSource with namespace support", 0, 1}, + {tFromTemplates, saxSourceWithoutNS, "SAXSource without namespace support", 3, 3}, + {t, staxSourceWithNS, "StAXSource with namespace support", 0, 1} + }; + } + + /* + * @bug 8169631 + * @summary Test combinations of namespace awareness settings on + * XSL transformations + */ + @Test(dataProvider = "testdata8169631") + public void run(Transformer t, Source s, String label, int elementcount, int attributecount) + throws TransformerException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + t.transform(s, new StreamResult(baos)); + verifyResult(label, baos.toString(), elementcount, attributecount); } } - /* - * @bug 8169631 - * @summary Test combinations of namespace awareness settings on - * XSL transformations - */ - @Test - public final void testBug8169631() throws IOException, SAXException, - TransformerException, ParserConfigurationException - { - new Test8169631().run(); + public static class Test8150704 extends TransformerTestTemplate { + + public Test8150704() { + super(); + } + + @DataProvider(name = "testdata8150704") + public Object[][] testData() { + return new Object[][] { + {"Bug8150704-1.xsl", "Bug8150704-1.xml", "Bug8150704-1.ref"}, + {"Bug8150704-2.xsl", "Bug8150704-2.xml", "Bug8150704-2.ref"} + }; + } + + /* + * @bug 8150704 + * @summary Test that XSL transformation with lots of temporary result + * trees will not run out of DTM IDs. + */ + @Test(dataProvider = "testdata8150704") + public void run(String xsl, String xml, String ref) throws IOException, TransformerException { + System.out.println("Testing transformation of " + xml + "..."); + setXsl(fromInputStream(getClass().getResourceAsStream(xsl))); + setSourceXml(fromInputStream(getClass().getResourceAsStream(xml))); + Transformer t = getTransformer(); + StringWriter resultWriter = new StringWriter(); + t.transform(getStreamSource(), new StreamResult(resultWriter)); + String resultString = resultWriter.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n").trim(); + String reference = fromInputStream(getClass().getResourceAsStream(ref)).trim(); + Assert.assertEquals(resultString, reference, "Output of transformation of " + xml + " does not match reference"); + System.out.println("Passed."); + } } - /* - * @bug 8150704 - * @summary Test that XSL transformation with lots of temporary result - * trees will not run out of DTM IDs. - */ - @Test - public final void testBug8150704() throws TransformerException, IOException { - System.out.println("Testing transformation of Bug8150704-1.xml..."); - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer t = tf.newTransformer(new StreamSource(getClass().getResource("Bug8150704-1.xsl").toString())); - StringWriter sw = new StringWriter(); - t.transform(new StreamSource(getClass().getResource("Bug8150704-1.xml").toString()), new StreamResult(sw)); - String resultstring = sw.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n"); - String reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-1.ref").getPath())); - Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-1.xml does not match reference"); - System.out.println("Passed."); + public static class Test8162598 extends TransformerTestTemplate { - System.out.println("Testing transformation of Bug8150704-2.xml..."); - t = tf.newTransformer(new StreamSource(getClass().getResource("Bug8150704-2.xsl").toString())); - sw = new StringWriter(); - t.transform(new StreamSource(getClass().getResource("Bug8150704-2.xml").toString()), new StreamResult(sw)); - resultstring = sw.toString().replaceAll("\\r\\n", "\n").replaceAll("\\r", "\n"); - reference = getFileContentAsString(new File(getClass().getResource("Bug8150704-2.ref").getPath())); - Assert.assertEquals(resultstring, reference, "Output of transformation of Bug8150704-2.xml does not match reference"); - System.out.println("Passed."); - } - - private static class Test8162598 extends TestTemplate { - private static final String xsl = + private static String XSL_INPUT = "" + LINE_SEPARATOR + "" + LINE_SEPARATOR + " " + LINE_SEPARATOR + @@ -494,8 +489,13 @@ public class TransformerTest { " " + LINE_SEPARATOR + ""; - private static final String sourceXml = + private static String XML_INPUT = "" + LINE_SEPARATOR; + + public Test8162598() { + super(XSL_INPUT, XML_INPUT); + } + /** * Utility method for testBug8162598(). * Provides a convenient way to check/assert the expected namespaces @@ -510,7 +510,6 @@ public class TransformerTest { * @param nsc * Expected namespace of the first sibling of the first sibling */ - private void checkNodeNS(Node test, String nstest, String nsb, String nsc) { String testNodeName = test.getNodeName(); if (nstest == null) { @@ -532,29 +531,27 @@ public class TransformerTest { } } + /* + * @bug 8162598 + * @summary Test XSLTC handling of namespaces, especially empty namespace + * definitions to reset the default namespace + */ + @Test public void run() throws Exception { - printSnippet("Source:", sourceXml); - - printSnippet("Stylesheet:", xsl); + // print input + printSnippet("Source:", getSourceXml()); + printSnippet("Stylesheet:", getXsl()); // transform to DOM result - TransformerFactory tf = TransformerFactory.newInstance(); - ByteArrayInputStream bais = new ByteArrayInputStream(xsl.getBytes()); - Transformer t = tf.newTransformer(new StreamSource(bais)); + Transformer t = getTransformer(); DOMResult result = new DOMResult(); - bais = new ByteArrayInputStream(sourceXml.getBytes()); - t.transform(new StreamSource(bais), result); + t.transform(getStreamSource(), result); + + // print output + printSnippet("Result after transformation:", prettyPrintDOMResult(result)); + + // do some verifications Document document = (Document)result.getNode(); - - System.out.println("Result after transformation:"); - System.out.println("============================"); - tryRunWithTmpPermission(() -> { - OutputFormat format = new OutputFormat(); - format.setIndenting(true); - new XMLSerializer(System.out, format).serialize(document); - }, new RuntimePermission("accessClassInPackage.com.sun.org.apache.xml.internal.serialize")); - System.out.println(); - checkNodeNS(document.getElementsByTagName("test1").item(0), "ns2", "ns2", null); checkNodeNS(document.getElementsByTagName("test2").item(0), "ns1", "ns2", null); checkNodeNS(document.getElementsByTagName("test3").item(0), null, null, null); @@ -565,68 +562,74 @@ public class TransformerTest { } } - /* - * @bug 8162598 - * @summary Test XSLTC handling of namespaces, especially empty namespace - * definitions to reset the default namespace - */ - @Test - public final void testBug8162598() throws Exception { - new Test8162598().run(); + public static class Test8169112 extends TransformerTestTemplate{ + + public static String XML_INPUT = + ""; + + public Test8169112() throws IOException { + super(); + setXsl(fromInputStream(getClass().getResourceAsStream("Bug8169112.xsl"))); + setSourceXml(XML_INPUT); + } + + /** + * @throws TransformerException + * @bug 8169112 + * @summary Test compilation of large xsl file with outlining. + * + * This test merely compiles a large xsl file and tests if its bytecode + * passes verification by invoking the transform() method for + * dummy content. The test succeeds if no Exception is thrown + */ + @Test + public void run() throws TransformerException { + Transformer t = getTransformer(); + t.transform(getStreamSource(), new StreamResult(new ByteArrayOutputStream())); + } } - /** - * @bug 8169112 - * @summary Test compilation of large xsl file with outlining. - * - * This test merely compiles a large xsl file and tests if its bytecode - * passes verification by invoking the transform() method for - * dummy content. The test succeeds if no Exception is thrown - */ - @Test - public final void testBug8169112() throws FileNotFoundException, - TransformerException - { - TransformerFactory tf = TransformerFactory.newInstance(); - String xslFile = getClass().getResource("Bug8169112.xsl").toString(); - Transformer t = tf.newTransformer(new StreamSource(xslFile)); - String xmlIn = ""; - ByteArrayInputStream bis = new ByteArrayInputStream(xmlIn.getBytes()); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - t.transform(new StreamSource(bis), new StreamResult(bos)); - } + public static class Test8169772 extends TransformerTestTemplate { - /** - * @bug 8169772 - * @summary Test transformation of DOM with null valued text node - * - * This test would throw a NullPointerException during transform when the - * fix was not present. - */ - @Test - public final void testBug8169772() throws ParserConfigurationException, - SAXException, IOException, TransformerException - { - // create a small DOM - Document doc = DocumentBuilderFactory.newInstance(). - newDocumentBuilder().parse( - new ByteArrayInputStream( - "".getBytes() - ) - ); + public Test8169772() { + super(); + } - // insert a bad element - Element e = doc.createElement("ERROR"); - e.appendChild(doc.createTextNode(null)); - doc.getDocumentElement().appendChild(e); + private Document getDOMWithBadElement() throws SAXException, IOException, ParserConfigurationException { + // create a small DOM + Document doc = DocumentBuilderFactory.newInstance(). + newDocumentBuilder().parse( + new ByteArrayInputStream( + "".getBytes() + ) + ); - // transform - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - TransformerFactory.newInstance().newTransformer().transform( - new DOMSource(doc.getDocumentElement()), new StreamResult(bos) - ); - System.out.println("Transformation result (DOM with null text node):"); - System.out.println("================================================"); - System.out.println(bos); + // insert a bad element + Element e = doc.createElement("ERROR"); + e.appendChild(doc.createTextNode(null)); + doc.getDocumentElement().appendChild(e); + + return doc; + } + + /** + * @throws ParserConfigurationException + * @throws IOException + * @throws SAXException + * @throws TransformerException + * @bug 8169772 + * @summary Test transformation of DOM with null valued text node + * + * This test would throw a NullPointerException during transform when the + * fix was not present. + */ + @Test + public void run() throws SAXException, IOException, ParserConfigurationException, TransformerException { + Transformer t = getTransformer(); + StringWriter resultWriter = new StringWriter(); + DOMSource d = new DOMSource(getDOMWithBadElement().getDocumentElement()); + t.transform(d, new StreamResult(resultWriter)); + printSnippet("Transformation result (DOM with null text node):", resultWriter.toString()); + } } } diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/util/TransformerTestTemplate.java b/jaxp/test/javax/xml/jaxp/unittest/transform/util/TransformerTestTemplate.java new file mode 100644 index 00000000000..a102a21f4e2 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/util/TransformerTestTemplate.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 transform.util; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.stream.Collectors; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +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.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/* + * Template for Transformer tests + */ +public abstract class TransformerTestTemplate { + private String xsl = null; + private String sourceXml = null; + + public TransformerTestTemplate() { + super(); + } + + public TransformerTestTemplate(String xsl, String sourceXml) { + super(); + this.xsl = xsl; + this.sourceXml = sourceXml; + } + + public String getXsl() { + return xsl; + } + + public void setXsl(String xsl) { + this.xsl = xsl; + } + + public String getSourceXml() { + return sourceXml; + } + + public void setSourceXml(String sourceXml) { + this.sourceXml = sourceXml; + } + + public String fromInputStream(InputStream is) throws IOException { + try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + return br.lines().collect(Collectors.joining("\n")); + } + } + + // print an XML Snippet under a given title + public void printSnippet(String title, String snippet) { + StringBuilder div = new StringBuilder(); + for (int i = 0; i < title.length(); i++) + div.append("="); + System.out.println(title + "\n" + div + "\n" + snippet + "\n"); + } + + // pretty print a DOMResult + public String prettyPrintDOMResult(DOMResult dr) throws ClassNotFoundException, InstantiationException, + IllegalAccessException, ClassCastException + { + DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance(); + DOMImplementationLS domImplementationLS = (DOMImplementationLS)registry.getDOMImplementation("LS"); + StringWriter writer = new StringWriter(); + LSOutput formattedOutput = domImplementationLS.createLSOutput(); + formattedOutput.setCharacterStream(writer); + LSSerializer domSerializer = domImplementationLS.createLSSerializer(); + domSerializer.getDomConfig().setParameter("format-pretty-print", true); + domSerializer.getDomConfig().setParameter("xml-declaration", false); + domSerializer.write(dr.getNode(), formattedOutput); + return writer.toString(); + } + + public Transformer getTransformer() throws TransformerConfigurationException { + return getTransformer(null); + } + + // utility to obtain Transformer from TransformerFactory + public Transformer getTransformer(TransformerFactory tf) + throws TransformerConfigurationException + { + if (tf == null) { + tf = TransformerFactory.newInstance(); + } + + if (xsl == null) { + return tf.newTransformer(); + } else { + return tf.newTransformer( + new StreamSource(new ByteArrayInputStream(xsl.getBytes())) + ); + } + } + + // utility to obtain Templates from TransformerFactory + public Templates getTemplates(TransformerFactory tf) + throws TransformerConfigurationException + { + return tf.newTemplates( + new StreamSource(new ByteArrayInputStream(xsl.getBytes())) + ); + } + + // utility to construct StreamSource + public StreamSource getStreamSource() { + return new StreamSource( + new ByteArrayInputStream(sourceXml.getBytes()) + ); + } + + // utility to construct DOMSource from DocumentBuilderFactory + public DOMSource getDOMSource(DocumentBuilderFactory dbf) + throws SAXException, IOException, ParserConfigurationException + { + return new DOMSource( + dbf.newDocumentBuilder().parse( + new InputSource( + new ByteArrayInputStream(sourceXml.getBytes()) + ) + ) + ); + } + + // utility to construct SAXSource from SAXParserFactory + public SAXSource getSAXSource(SAXParserFactory spf) + throws SAXException, ParserConfigurationException + { + return new SAXSource( + spf.newSAXParser().getXMLReader(), + new InputSource(new ByteArrayInputStream(sourceXml.getBytes())) + ); + } + + // utility to construct StAXSource from XMLInputFactory + public StAXSource getStAXSource(XMLInputFactory xif) + throws XMLStreamException + { + return new StAXSource( + xif.createXMLStreamReader(new StringReader(sourceXml)) + ); + } +} diff --git a/jaxws/.hgtags b/jaxws/.hgtags index fd2f5b815b4..b130a70170d 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -400,3 +400,4 @@ c48b4d4768b1c2b8fe5d1a844ca13732e5dfbe2a jdk-9+151 6f8fb1cf7e5f61c40dcc3654f9a623c505f6de1f jdk-9+152 7a532a9a227137155b905341d4b99939db51220e jdk-9+153 34af95c7dbff74f3448fcdb7d745524e8a1cc88a jdk-9+154 +9b9918656c97724fd89c04a8547043bbd37f5935 jdk-9+155 diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/Generated.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Generated.java similarity index 100% rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/Generated.java rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Generated.java diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/PostConstruct.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PostConstruct.java similarity index 100% rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/PostConstruct.java rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PostConstruct.java diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/PreDestroy.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PreDestroy.java similarity index 100% rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/PreDestroy.java rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/PreDestroy.java diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/Resource.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resource.java similarity index 100% rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/Resource.java rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resource.java diff --git a/jaxws/src/java.annotations.common/share/classes/javax/annotation/Resources.java b/jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resources.java similarity index 100% rename from jaxws/src/java.annotations.common/share/classes/javax/annotation/Resources.java rename to jaxws/src/java.xml.ws.annotation/share/classes/javax/annotation/Resources.java diff --git a/jaxws/src/java.annotations.common/share/classes/module-info.java b/jaxws/src/java.xml.ws.annotation/share/classes/module-info.java similarity index 91% rename from jaxws/src/java.annotations.common/share/classes/module-info.java rename to jaxws/src/java.xml.ws.annotation/share/classes/module-info.java index fddb78c5efc..58a625918fe 100644 --- a/jaxws/src/java.annotations.common/share/classes/module-info.java +++ b/jaxws/src/java.xml.ws.annotation/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +27,7 @@ * Defines a subset of the Common Annotations API to support programs running * on the Java SE Platform. */ -module java.annotations.common { +module java.xml.ws.annotation { exports javax.annotation; } diff --git a/jaxws/src/java.xml.ws/share/classes/module-info.java b/jaxws/src/java.xml.ws/share/classes/module-info.java index def2ec6be19..4a0175eeae2 100644 --- a/jaxws/src/java.xml.ws/share/classes/module-info.java +++ b/jaxws/src/java.xml.ws/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ module java.xml.ws { requires transitive java.activation; requires transitive java.xml; requires transitive java.xml.bind; - requires java.annotations.common; + requires java.xml.ws.annotation; requires java.desktop; requires java.logging; requires java.management; diff --git a/jdk/.hgtags b/jdk/.hgtags index 5a7c6ba2850..e6379a2ee4f 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -398,3 +398,4 @@ a20f2cf90762673e1bc4980fd6597e70a2578045 jdk-9+152 1c4411322327aea3f91011ec3977a12a05b09629 jdk-9+153 c97e7a8b8da062b9070df442f9cf308e10845fb7 jdk-9+154 e170c858888e83d5c0994504599b6ed7a1fb0cfc jdk-9+155 +7d64e541a6c04c714bcad4c8b553db912f827cd5 jdk-9+156 diff --git a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java index 4de7b5c719a..ac1f9b86090 100644 --- a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java +++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java @@ -153,9 +153,9 @@ public class GenGraphs { */ void genDotFile(String name, Set roots) throws IOException { Configuration cf = - Configuration.empty().resolveRequires(ModuleFinder.ofSystem(), - ModuleFinder.of(), - roots); + Configuration.empty().resolve(ModuleFinder.ofSystem(), + ModuleFinder.of(), + roots); Set mds = cf.modules().stream() .map(ResolvedModule::reference) diff --git a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java index e55a1c04855..520fb1b96b0 100644 --- a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java +++ b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java @@ -291,9 +291,9 @@ public class ModuleSummary { static Configuration resolve(Set roots) { return Configuration.empty() - .resolveRequires(ModuleFinder.ofSystem(), - ModuleFinder.of(), - roots); + .resolve(ModuleFinder.ofSystem(), + ModuleFinder.of(), + roots); } static class HtmlDocument { diff --git a/jdk/src/java.base/aix/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/aix/classes/sun/nio/fs/DefaultFileSystemProvider.java new file mode 100644 index 00000000000..8c33d7e5a59 --- /dev/null +++ b/jdk/src/java.base/aix/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileSystemProvider; + +/** + * Creates this platform's default FileSystemProvider. + */ + +public class DefaultFileSystemProvider { + private DefaultFileSystemProvider() { } + + /** + * Returns the default FileSystemProvider. + */ + public static FileSystemProvider create() { + return new AixFileSystemProvider(); + } +} diff --git a/jdk/src/java.base/linux/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/linux/classes/sun/nio/fs/DefaultFileSystemProvider.java new file mode 100644 index 00000000000..82a06b7ea50 --- /dev/null +++ b/jdk/src/java.base/linux/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileSystemProvider; + +/** + * Creates this platform's default FileSystemProvider. + */ + +public class DefaultFileSystemProvider { + private DefaultFileSystemProvider() { } + + /** + * Returns the default FileSystemProvider. + */ + public static FileSystemProvider create() { + return new LinuxFileSystemProvider(); + } +} diff --git a/jdk/src/java.base/macosx/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/macosx/classes/sun/nio/fs/DefaultFileSystemProvider.java new file mode 100644 index 00000000000..917d9f3a25b --- /dev/null +++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileSystemProvider; + +/** + * Creates this platform's default FileSystemProvider. + */ + +public class DefaultFileSystemProvider { + private DefaultFileSystemProvider() { } + + /** + * Returns the default FileSystemProvider. + */ + public static FileSystemProvider create() { + return new MacOSXFileSystemProvider(); + } +} diff --git a/jdk/src/java.base/share/classes/java/lang/Class.java b/jdk/src/java.base/share/classes/java/lang/Class.java index b0e3d3af0cd..0a3b1da91a1 100644 --- a/jdk/src/java.base/share/classes/java/lang/Class.java +++ b/jdk/src/java.base/share/classes/java/lang/Class.java @@ -425,6 +425,7 @@ public final class Class implements java.io.Serializable, * * * @since 9 + * @spec JPMS */ @CallerSensitive public static Class forName(Module module, String name) { @@ -819,6 +820,7 @@ public final class Class implements java.io.Serializable, * @return the module that this class or interface is a member of * * @since 9 + * @spec JPMS */ public Module getModule() { return module; @@ -924,6 +926,8 @@ public final class Class implements java.io.Serializable, * this method returns {@code null}. * * @return the package of this class. + * @revised 9 + * @spec JPMS */ public Package getPackage() { if (isPrimitive() || isArray()) { @@ -951,20 +955,30 @@ public final class Class implements java.io.Serializable, * declaring class} of the {@link #getEnclosingMethod enclosing method} or * {@link #getEnclosingConstructor enclosing constructor}. * - *

This method returns {@code null} if this class represents an array type, - * a primitive type or void. + *

If this class represents an array type then this method returns the + * package name of the element type. If this class represents a primitive + * type or void then the package name "{@code java.lang}" is returned. * * @return the fully qualified package name * * @since 9 + * @spec JPMS * @jls 6.7 Fully Qualified Names */ public String getPackageName() { String pn = this.packageName; - if (pn == null && !isArray() && !isPrimitive()) { - String cn = getName(); - int dot = cn.lastIndexOf('.'); - pn = (dot != -1) ? cn.substring(0, dot).intern() : ""; + if (pn == null) { + Class c = this; + while (c.isArray()) { + c = c.getComponentType(); + } + if (c.isPrimitive()) { + pn = "java.lang"; + } else { + String cn = c.getName(); + int dot = cn.lastIndexOf('.'); + pn = (dot != -1) ? cn.substring(0, dot).intern() : ""; + } this.packageName = pn; } return pn; @@ -2491,10 +2505,16 @@ public final class Class implements java.io.Serializable, * Finds a resource with a given name. * *

If this class is in a named {@link Module Module} then this method - * will attempt to find the resource in the module by means of the absolute - * resource name, subject to the rules for encapsulation specified in the - * {@code Module} {@link Module#getResourceAsStream getResourceAsStream} - * method. + * will attempt to find the resource in the module. This is done by + * delegating to the module's class loader {@link + * ClassLoader#findResource(String,String) findResource(String,String)} + * method, invoking it with the module name and the absolute name of the + * resource. Resources in named modules are subject to the rules for + * encapsulation specified in the {@code Module} {@link + * Module#getResourceAsStream getResourceAsStream} method and so this + * method returns {@code null} when the resource is a + * non-"{@code .class}" resource in a package that is not open to the + * caller's module. * *

Otherwise, if this class is not in a named module then the rules for * searching resources associated with a given class are implemented by the @@ -2503,9 +2523,8 @@ public final class Class implements java.io.Serializable, * the bootstrap class loader, the method delegates to {@link * ClassLoader#getSystemResourceAsStream}. * - *

Before finding a resource in the caller's module or delegation to a - * class loader, an absolute resource name is constructed from the given - * resource name using this algorithm: + *

Before delegation, an absolute resource name is constructed from the + * given resource name using this algorithm: * *

    * @@ -2532,7 +2551,11 @@ public final class Class implements java.io.Serializable, * least the caller module, or access to the resource is denied * by the security manager. * @throws NullPointerException If {@code name} is {@code null} + * + * @see Module#getResourceAsStream(String) * @since 1.1 + * @revised 9 + * @spec JPMS */ @CallerSensitive public InputStream getResourceAsStream(String name) { @@ -2585,10 +2608,16 @@ public final class Class implements java.io.Serializable, * Finds a resource with a given name. * *

    If this class is in a named {@link Module Module} then this method - * will attempt to find the resource in the module by means of the absolute - * resource name, subject to the rules for encapsulation specified in the - * {@code Module} {@link Module#getResourceAsStream getResourceAsStream} - * method. + * will attempt to find the resource in the module. This is done by + * delegating to the module's class loader {@link + * ClassLoader#findResource(String,String) findResource(String,String)} + * method, invoking it with the module name and the absolute name of the + * resource. Resources in named modules are subject to the rules for + * encapsulation specified in the {@code Module} {@link + * Module#getResourceAsStream getResourceAsStream} method and so this + * method returns {@code null} when the resource is a + * non-"{@code .class}" resource in a package that is not open to the + * caller's module. * *

    Otherwise, if this class is not in a named module then the rules for * searching resources associated with a given class are implemented by the @@ -2627,6 +2656,8 @@ public final class Class implements java.io.Serializable, * manager. * @throws NullPointerException If {@code name} is {@code null} * @since 1.1 + * @revised 9 + * @spec JPMS */ @CallerSensitive public URL getResource(String name) { diff --git a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java index fb771c29a10..06da4a983e1 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -207,6 +207,8 @@ import sun.security.util.SecurityConstants; * @jls 13.1 The Form of a Binary * @see #resolveClass(Class) * @since 1.0 + * @revised 9 + * @spec JPMS */ public abstract class ClassLoader { @@ -380,12 +382,12 @@ public abstract class ClassLoader { * method doesn't allow creation of a new class loader. * * @since 9 + * @spec JPMS */ protected ClassLoader(String name, ClassLoader parent) { this(checkCreateClassLoader(name), name, parent); } - /** * Creates a new class loader using the specified parent class loader for * delegation. @@ -440,6 +442,7 @@ public abstract class ClassLoader { * this class loader is not named. * * @since 9 + * @spec JPMS */ public String getName() { return name; @@ -710,6 +713,7 @@ public abstract class ClassLoader { * if the class could not be found. * * @since 9 + * @spec JPMS */ protected Class findClass(String moduleName, String name) { if (moduleName == null) { @@ -834,6 +838,8 @@ public abstract class ClassLoader { * @see java.security.SecureClassLoader * * @since 1.1 + * @revised 9 + * @spec JPMS */ protected final Class defineClass(String name, byte[] b, int off, int len) throws ClassFormatError @@ -967,6 +973,9 @@ public abstract class ClassLoader { * certificates than this class, or if {@code name} begins with * "{@code java.}" and this class loader is not the platform * class loader or its ancestor. + * + * @revised 9 + * @spec JPMS */ protected final Class defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) @@ -1041,6 +1050,8 @@ public abstract class ClassLoader { * @see #defineClass(String, byte[], int, int, ProtectionDomain) * * @since 1.5 + * @revised 9 + * @spec JPMS */ protected final Class defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain) @@ -1264,11 +1275,11 @@ public abstract class ClassLoader { * Class loader implementations that support the loading from modules * should override this method. * - * @apiNote This method is the basis for the {@code Class} {@link - * Class#getResource getResource} and {@link Class#getResourceAsStream - * getResourceAsStream} methods. It is not subject to the rules for - * encapsulation specified by {@code Module} {@link - * Module#getResourceAsStream getResourceAsStream}. + * @apiNote This method is the basis for the {@link + * Class#getResource Class.getResource}, {@link Class#getResourceAsStream + * Class.getResourceAsStream}, and {@link Module#getResourceAsStream + * Module.getResourceAsStream} methods. It is not subject to the rules for + * encapsulation specified by {@code Module.getResourceAsStream}. * * @implSpec The default implementation attempts to find the resource by * invoking {@link #findResource(String)} when the {@code moduleName} is @@ -1292,6 +1303,7 @@ public abstract class ClassLoader { * * @see java.lang.module.ModuleReader#find(String) * @since 9 + * @spec JPMS */ protected URL findResource(String moduleName, String name) throws IOException { if (moduleName == null) { @@ -1342,6 +1354,8 @@ public abstract class ClassLoader { * @throws NullPointerException If {@code name} is {@code null} * * @since 1.1 + * @revised 9 + * @spec JPMS */ public URL getResource(String name) { Objects.requireNonNull(name); @@ -1403,6 +1417,8 @@ public abstract class ClassLoader { * @see #findResources(String) * * @since 1.2 + * @revised 9 + * @spec JPMS */ public Enumeration getResources(String name) throws IOException { Objects.requireNonNull(name); @@ -1499,6 +1515,8 @@ public abstract class ClassLoader { * denied by the security manager. * * @since 1.2 + * @revised 9 + * @spec JPMS */ protected URL findResource(String name) { return null; @@ -1531,6 +1549,8 @@ public abstract class ClassLoader { * If I/O errors occur * * @since 1.2 + * @revised 9 + * @spec JPMS */ protected Enumeration findResources(String name) throws IOException { return Collections.emptyEnumeration(); @@ -1601,6 +1621,8 @@ public abstract class ClassLoader { * denied by the security manager. * * @since 1.1 + * @revised 9 + * @spec JPMS */ public static URL getSystemResource(String name) { return getSystemClassLoader().getResource(name); @@ -1636,6 +1658,8 @@ public abstract class ClassLoader { * If I/O errors occur * * @since 1.2 + * @revised 9 + * @spec JPMS */ public static Enumeration getSystemResources(String name) throws IOException @@ -1667,6 +1691,8 @@ public abstract class ClassLoader { * @throws NullPointerException If {@code name} is {@code null} * * @since 1.1 + * @revised 9 + * @spec JPMS */ public InputStream getResourceAsStream(String name) { Objects.requireNonNull(name); @@ -1699,6 +1725,8 @@ public abstract class ClassLoader { * denied by the security manager. * * @since 1.1 + * @revised 9 + * @spec JPMS */ public static InputStream getSystemResourceAsStream(String name) { URL url = getSystemResource(name); @@ -1749,6 +1777,7 @@ public abstract class ClassLoader { * * @see Module#isNamed() * @since 9 + * @spec JPMS */ public final Module getUnnamedModule() { return unnamedModule; @@ -1772,6 +1801,7 @@ public abstract class ClassLoader { * {@link RuntimePermission}{@code ("getClassLoader")} * * @since 9 + * @spec JPMS */ @CallerSensitive public static ClassLoader getPlatformClassLoader() { @@ -1847,6 +1877,8 @@ public abstract class ClassLoader { * {@link Throwable#getCause()} method. * * @revised 1.4 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ClassLoader getSystemClassLoader() { @@ -2101,6 +2133,8 @@ public abstract class ClassLoader { * defined by this class loader * * @since 1.2 + * @revised 9 + * @spec JPMS * * @see * The JAR File Specification: Package Versioning @@ -2138,6 +2172,7 @@ public abstract class ClassLoader { * if {@code name} is {@code null}. * * @since 9 + * @spec JPMS */ public final Package getDefinedPackage(String name) { Objects.requireNonNull(name, "name cannot be null"); @@ -2160,6 +2195,7 @@ public abstract class ClassLoader { * or an zero length array if no package has been defined by this class loader. * * @since 9 + * @spec JPMS */ public final Package[] getDefinedPackages() { return packages().toArray(Package[]::new); @@ -2196,6 +2232,8 @@ public abstract class ClassLoader { * a {@code Package} for the specified class loader. * * @since 1.2 + * @revised 9 + * @spec JPMS */ @Deprecated(since="9") protected Package getPackage(String name) { @@ -2220,6 +2258,8 @@ public abstract class ClassLoader { * class loader and its ancestors * * @since 1.2 + * @revised 9 + * @spec JPMS */ protected Package[] getPackages() { Stream pkgs = packages(); diff --git a/jdk/src/java.base/share/classes/java/lang/IllegalCallerException.java b/jdk/src/java.base/share/classes/java/lang/IllegalCallerException.java new file mode 100644 index 00000000000..f882fb21591 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/IllegalCallerException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 java.lang; + +/** + * Thrown to indicate that a method has been called by an inappropriate caller. + * + * @since 9 + * @spec JPMS + * @see StackWalker#getCallerClass + */ +public class IllegalCallerException extends RuntimeException { + /** + * Constructs an IllegalCallerException with no detail message. + */ + public IllegalCallerException() { + super(); + } + + /** + * Constructs an IllegalCallerException with the specified detail + * message. + * + * @param s the String that contains a detailed message (can be null) + */ + public IllegalCallerException(String s) { + super(s); + } + + /** + * Constructs a new exception with the specified detail message and + * cause. + * + * @param message the detail message (can be null) + * @param cause the cause (can be null) + */ + public IllegalCallerException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructs a new exception with the specified cause and a detail + * message of {@code (cause==null ? null : cause.toString())} (which + * typically contains the class and detail message of {@code cause}). + * + * @param cause the cause (can be null) + */ + public IllegalCallerException(Throwable cause) { + super(cause); + } + + static final long serialVersionUID = -2349421918363102232L; +} diff --git a/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java b/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java index 5be48729d5a..612ff09f138 100644 --- a/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java +++ b/jdk/src/java.base/share/classes/java/lang/LiveStackFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,14 +55,36 @@ interface LiveStackFrame extends StackFrame { * *

    A single local variable can hold a value of type boolean, byte, char, * short, int, float, reference or returnAddress. A pair of local variables - * can hold a value of type long or double. In other words, - * a value of type long or type double occupies two consecutive local - * variables. For a value of primitive type, the element in the - * local variable array is an {@link PrimitiveValue} object; - * otherwise, the element is an {@code Object}. + * can hold a value of type long or double (JVMS section 2.6.1). Primitive + * locals are represented in the returned array as {@code PrimitiveSlot}s, + * with longs and doubles occupying a pair of consecutive + * {@code PrimitiveSlot}s. * - *

    The returned array may contain null entries if a local variable is not - * live. + *

    The current VM implementation does not provide specific type + * information for primitive locals. This method simply returns the raw + * contents of the VM's primitive locals on a best-effort basis, without + * indicating a specific type. + * + *

    The returned array may contain null entries for local variables that + * are not live. + * + * @implNote + *

    The specific subclass of {@code PrimitiveSlot} will reflect the + * underlying architecture, and will be either {@code PrimitiveSlot32} or + * {@code PrimitiveSlot64}. + * + *

    How a long or double value is stored in the pair of + * {@code PrimitiveSlot}s can vary based on the underlying architecture and + * VM implementation. On 32-bit architectures, long/double values are split + * between the two {@code PrimitiveSlot32}s. + * On 64-bit architectures, the entire value may be stored in one of the + * {@code PrimitiveSlot64}s, with the other {@code PrimitiveSlot64} being + * unused. + * + *

    The contents of the unused, high-order portion of a + * {@code PrimitiveSlot64} (when storing a primitive other than a long or + * double) is unspecified. In particular, the unused bits are not + * necessarily zeroed out. * * @return the local variable array of this stack frame. */ @@ -78,7 +100,7 @@ interface LiveStackFrame extends StackFrame { *

    Each entry on the operand stack can hold a value of any Java Virtual * Machine Type. * For a value of primitive type, the element in the returned array is - * an {@link PrimitiveValue} object; otherwise, the element is the {@code Object} + * a {@link PrimitiveSlot} object; otherwise, the element is the {@code Object} * on the operand stack. * * @return the operand stack of this stack frame. @@ -87,107 +109,37 @@ interface LiveStackFrame extends StackFrame { /** * UNSUPPORTED This interface is intended to be package-private - * or move to an internal package.

    + * or moved to an internal package.

    * - * Represents a local variable or an entry on the operand whose value is + * Represents a local variable or an entry on the operand stack whose value is * of primitive type. */ - public abstract class PrimitiveValue { + public abstract class PrimitiveSlot { /** - * Returns the base type of this primitive value, one of - * {@code B, D, C, F, I, J, S, Z}. - * - * @return Name of a base type - * @jvms table 4.3-A + * Returns the size, in bytes, of the slot. */ - abstract char type(); + public abstract int size(); /** - * Returns the boolean value if this primitive value is of type boolean. - * @return the boolean value if this primitive value is of type boolean. + * Returns the int value if this primitive value is of size 4 + * @return the int value if this primitive value is of size 4 * * @throws UnsupportedOperationException if this primitive value is not - * of type boolean. - */ - public boolean booleanValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the int value if this primitive value is of type int. - * @return the int value if this primitive value is of type int. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type int. + * of size 4. */ public int intValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); + throw new UnsupportedOperationException("this " + size() + "-byte primitive"); } /** - * Returns the long value if this primitive value is of type long. - * @return the long value if this primitive value is of type long. + * Returns the long value if this primitive value is of size 8 + * @return the long value if this primitive value is of size 8 * * @throws UnsupportedOperationException if this primitive value is not - * of type long. + * of size 8. */ public long longValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the char value if this primitive value is of type char. - * @return the char value if this primitive value is of type char. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type char. - */ - public char charValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the byte value if this primitive value is of type byte. - * @return the byte value if this primitive value is of type byte. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type byte. - */ - public byte byteValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the short value if this primitive value is of type short. - * @return the short value if this primitive value is of type short. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type short. - */ - public short shortValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the float value if this primitive value is of type float. - * @return the float value if this primitive value is of type float. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type float. - */ - public float floatValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); - } - - /** - * Returns the double value if this primitive value is of type double. - * @return the double value if this primitive value is of type double. - * - * @throws UnsupportedOperationException if this primitive value is not - * of type double. - */ - public double doubleValue() { - throw new UnsupportedOperationException("this primitive of type " + type()); + throw new UnsupportedOperationException("this " + size() + "-byte primitive"); } } diff --git a/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java index db8901ea731..b6583adf559 100644 --- a/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java +++ b/jdk/src/java.base/share/classes/java/lang/LiveStackFrameInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,13 @@ */ package java.lang; -import java.lang.StackWalker.Option; -import java.util.EnumSet; -import java.util.Set; - -import static java.lang.StackWalker.ExtendedOption.*; - final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame { private static Object[] EMPTY_ARRAY = new Object[0]; + // These flags must match the values maintained in the VM + private static final int MODE_INTERPRETED = 0x01; + private static final int MODE_COMPILED = 0x02; + LiveStackFrameInfo(StackWalker walker) { super(walker); } @@ -41,6 +39,7 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame private Object[] monitors = EMPTY_ARRAY; private Object[] locals = EMPTY_ARRAY; private Object[] operands = EMPTY_ARRAY; + private int mode = 0; @Override public Object[] getMonitors() { @@ -57,51 +56,44 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame return operands; } + @Override + public String toString() { + StringBuilder retVal = new StringBuilder(super.toString()); + if (mode != 0) { + retVal.append("("); + if ((mode & MODE_INTERPRETED) == MODE_INTERPRETED) { + retVal.append(" interpreted "); + } + if ((mode & MODE_COMPILED) == MODE_COMPILED) { + retVal.append(" compiled "); + } + retVal.append(")"); + } + return retVal.toString(); + } + /* - * Convert primitive value to {@code Primitive} object to represent + * Convert primitive value to {@code PrimitiveSlot} object to represent * a local variable or an element on the operand stack of primitive type. */ - static PrimitiveValue asPrimitive(boolean value) { - return new BooleanPrimitive(value); + + static PrimitiveSlot asPrimitive(int value) { + return new PrimitiveSlot32(value); } - static PrimitiveValue asPrimitive(int value) { - return new IntPrimitive(value); + static PrimitiveSlot asPrimitive(long value) { + return new PrimitiveSlot64(value); } - static PrimitiveValue asPrimitive(short value) { - return new ShortPrimitive(value); - } - - static PrimitiveValue asPrimitive(char value) { - return new CharPrimitive(value); - } - - static PrimitiveValue asPrimitive(byte value) { - return new BytePrimitive(value); - } - - static PrimitiveValue asPrimitive(long value) { - return new LongPrimitive(value); - } - - static PrimitiveValue asPrimitive(float value) { - return new FloatPrimitive(value); - } - - static PrimitiveValue asPrimitive(double value) { - return new DoublePrimitive(value); - } - - private static class IntPrimitive extends PrimitiveValue { + private static class PrimitiveSlot32 extends PrimitiveSlot { final int value; - IntPrimitive(int value) { + PrimitiveSlot32(int value) { this.value = value; } @Override - public char type() { - return 'I'; + public int size() { + return 4; } @Override @@ -115,103 +107,15 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame } } - private static class ShortPrimitive extends PrimitiveValue { - final short value; - ShortPrimitive(short value) { - this.value = value; - } - - @Override - public char type() { - return 'S'; - } - - @Override - public short shortValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class BooleanPrimitive extends PrimitiveValue { - final boolean value; - BooleanPrimitive(boolean value) { - this.value = value; - } - - @Override - public char type() { - return 'Z'; - } - - @Override - public boolean booleanValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class CharPrimitive extends PrimitiveValue { - final char value; - CharPrimitive(char value) { - this.value = value; - } - - @Override - public char type() { - return 'C'; - } - - @Override - public char charValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class BytePrimitive extends PrimitiveValue { - final byte value; - BytePrimitive(byte value) { - this.value = value; - } - - @Override - public char type() { - return 'B'; - } - - @Override - public byte byteValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class LongPrimitive extends PrimitiveValue { + private static class PrimitiveSlot64 extends PrimitiveSlot { final long value; - LongPrimitive(long value) { + PrimitiveSlot64(long value) { this.value = value; } @Override - public char type() { - return 'J'; + public int size() { + return 8; } @Override @@ -224,48 +128,4 @@ final class LiveStackFrameInfo extends StackFrameInfo implements LiveStackFrame return String.valueOf(value); } } - - private static class FloatPrimitive extends PrimitiveValue { - final float value; - FloatPrimitive(float value) { - this.value = value; - } - - @Override - public char type() { - return 'F'; - } - - @Override - public float floatValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } - - private static class DoublePrimitive extends PrimitiveValue { - final double value; - DoublePrimitive(double value) { - this.value = value; - } - - @Override - public char type() { - return 'D'; - } - - @Override - public double doubleValue() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - } } diff --git a/jdk/src/java.base/share/classes/java/lang/Package.java b/jdk/src/java.base/share/classes/java/lang/Package.java index 5a19f9771f1..0dcc5e1c12c 100644 --- a/jdk/src/java.base/share/classes/java/lang/Package.java +++ b/jdk/src/java.base/share/classes/java/lang/Package.java @@ -111,6 +111,8 @@ import jdk.internal.reflect.Reflection; * @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL) * * @since 1.2 + * @revised 9 + * @spec JPMS */ public class Package extends NamedPackage implements java.lang.reflect.AnnotatedElement { /** @@ -207,6 +209,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated * is returned if it is not known. * @return the vendor that implemented this package, {@code null} * is returned if it is not known. + * + * @revised 9 + * @spec JPMS */ public String getImplementationVendor() { return versionInfo.implVendor; @@ -334,6 +339,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated * a {@code Package} for the specified class loader. * * @see ClassLoader#getDefinedPackage + * + * @revised 9 + * @spec JPMS */ @CallerSensitive @Deprecated(since="9") @@ -356,6 +364,9 @@ public class Package extends NamedPackage implements java.lang.reflect.Annotated * class loader and its ancestors * * @see ClassLoader#getDefinedPackages + * + * @revised 9 + * @spec JPMS */ @CallerSensitive public static Package[] getPackages() { diff --git a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java index 8a819ee6db7..084d4661700 100644 --- a/jdk/src/java.base/share/classes/java/lang/SecurityManager.java +++ b/jdk/src/java.base/share/classes/java/lang/SecurityManager.java @@ -1457,6 +1457,18 @@ class SecurityManager { .collect(Collectors.toSet()); } + /** + * Called by java.security.Security + */ + static void invalidatePackageAccessCache() { + synchronized (packageAccessLock) { + packageAccessValid = false; + } + synchronized (packageDefinitionLock) { + packageDefinitionValid = false; + } + } + /** * Returns true if the module's loader is the boot or platform loader. */ diff --git a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java index 55976485d4f..4fd03331229 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java @@ -25,11 +25,13 @@ package java.lang; import jdk.internal.reflect.MethodAccessor; +import jdk.internal.reflect.ConstructorAccessor; import java.lang.StackWalker.Option; import java.lang.StackWalker.StackFrame; import java.lang.annotation.Native; import java.lang.reflect.Method; +import java.lang.reflect.Constructor; import java.util.HashSet; import java.util.NoSuchElementException; import java.util.Objects; @@ -684,7 +686,7 @@ final class StackStreamFactory { frames[n++] = caller; } if (frames[1] == null) { - throw new IllegalStateException("no caller frame"); + throw new IllegalCallerException("no caller frame"); } return n; } @@ -922,7 +924,8 @@ final class StackStreamFactory { */ final void setBatch(int depth, int startIndex, int endIndex) { if (startIndex <= 0 || endIndex <= 0) - throw new IllegalArgumentException("startIndex=" + startIndex + " endIndex=" + endIndex); + throw new IllegalArgumentException("startIndex=" + startIndex + + " endIndex=" + endIndex); this.origin = startIndex; this.fence = endIndex; @@ -980,13 +983,18 @@ final class StackStreamFactory { private static boolean isReflectionFrame(Class c) { if (c.getName().startsWith("jdk.internal.reflect") && - !MethodAccessor.class.isAssignableFrom(c)) { - throw new InternalError("Not jdk.internal.reflect.MethodAccessor: " + c.toString()); + !MethodAccessor.class.isAssignableFrom(c) && + !ConstructorAccessor.class.isAssignableFrom(c)) { + throw new InternalError("Not jdk.internal.reflect.MethodAccessor" + + " or jdk.internal.reflect.ConstructorAccessor: " + + c.toString()); } // ## should filter all @Hidden frames? return c == Method.class || - MethodAccessor.class.isAssignableFrom(c) || - c.getName().startsWith("java.lang.invoke.LambdaForm"); + c == Constructor.class || + MethodAccessor.class.isAssignableFrom(c) || + ConstructorAccessor.class.isAssignableFrom(c) || + c.getName().startsWith("java.lang.invoke.LambdaForm"); } } diff --git a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java index d95ea5ef826..79b4c7299f6 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java +++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java @@ -92,6 +92,8 @@ public final class StackTraceElement implements java.io.Serializable { * @throws NullPointerException if {@code declaringClass} or * {@code methodName} is null * @since 1.5 + * @revised 9 + * @spec JPMS */ public StackTraceElement(String declaringClass, String methodName, String fileName, int lineNumber) { @@ -128,6 +130,7 @@ public final class StackTraceElement implements java.io.Serializable { * or {@code methodName} is {@code null} * * @since 9 + * @spec JPMS */ public StackTraceElement(String classLoaderName, String moduleName, String moduleVersion, @@ -187,6 +190,7 @@ public final class StackTraceElement implements java.io.Serializable { * point represented by this stack trace element; {@code null} * if the module name is not available. * @since 9 + * @spec JPMS * @see java.lang.reflect.Module#getName() */ public String getModuleName() { @@ -201,6 +205,7 @@ public final class StackTraceElement implements java.io.Serializable { * point represented by this stack trace element; {@code null} * if the module version is not available. * @since 9 + * @spec JPMS * @see java.lang.module.ModuleDescriptor.Version */ public String getModuleVersion() { @@ -216,6 +221,7 @@ public final class StackTraceElement implements java.io.Serializable { * if the class loader is not named. * * @since 9 + * @spec JPMS * @see java.lang.ClassLoader#getName() */ public String getClassLoaderName() { @@ -329,6 +335,8 @@ public final class StackTraceElement implements java.io.Serializable { * {@link java.lang.StackWalker.StackFrame}, where an implementation may * choose to omit some element in the returned string. * + * @revised 9 + * @spec JPMS * @see Throwable#printStackTrace() */ public String toString() { @@ -376,6 +384,9 @@ public final class StackTraceElement implements java.io.Serializable { * @return true if the specified object is another * {@code StackTraceElement} instance representing the same * execution point as this instance. + * + * @revised 9 + * @spec JPMS */ public boolean equals(Object obj) { if (obj==this) diff --git a/jdk/src/java.base/share/classes/java/lang/StackWalker.java b/jdk/src/java.base/share/classes/java/lang/StackWalker.java index b5c43fd2d67..52d9637c138 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackWalker.java +++ b/jdk/src/java.base/share/classes/java/lang/StackWalker.java @@ -29,6 +29,7 @@ import jdk.internal.reflect.CallerSensitive; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Predicate; import java.util.stream.Stream; /** @@ -207,13 +208,23 @@ public final class StackWalker { /** * Shows all reflection frames. * - *

    By default, reflection frames are hidden. This includes the - * {@link java.lang.reflect.Method#invoke} method - * and the reflection implementation classes. A {@code StackWalker} with - * this {@code SHOW_REFLECT_FRAMES} option will show all reflection frames. - * The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all + *

    By default, reflection frames are hidden. A {@code StackWalker} + * configured with this {@code SHOW_REFLECT_FRAMES} option + * will show all reflection frames that + * include {@link java.lang.reflect.Method#invoke} and + * {@link java.lang.reflect.Constructor#newInstance(Object...)} + * and their reflection implementation classes. + * + *

    The {@link #SHOW_HIDDEN_FRAMES} option can also be used to show all * reflection frames and it will also show other hidden frames that * are implementation-specific. + * + * @apiNote + * This option includes the stack frames representing the invocation of + * {@code Method} and {@code Constructor}. Any utility methods that + * are equivalent to calling {@code Method.invoke} or + * {@code Constructor.newInstance} such as {@code Class.newInstance} + * are not filtered or controlled by any stack walking option. */ SHOW_REFLECT_FRAMES, /** @@ -465,28 +476,31 @@ public final class StackWalker { } /** - * Gets the {@code Class} object of the caller invoking the method - * that calls this {@code getCallerClass} method. + * Gets the {@code Class} object of the caller who invoked the method + * that invoked {@code getCallerClass}. * - *

    Reflection frames, {@link java.lang.invoke.MethodHandle}, and - * hidden frames are filtered regardless of the + *

    This method filters {@linkplain Option#SHOW_REFLECT_FRAMES reflection + * frames}, {@link java.lang.invoke.MethodHandle}, and + * {@linkplain Option#SHOW_HIDDEN_FRAMES hidden frames} regardless of the * {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES} * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options * this {@code StackWalker} has been configured with. * + *

    This method should be called when a caller frame is present. If + * it is called from the bottom most frame on the stack, + * {@code IllegalCallerException} will be thrown. + * *

    This method throws {@code UnsupportedOperationException} * if this {@code StackWalker} is not configured with the * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option. - * This method should be called when a caller frame is present. If - * it is called from the last frame on the stack, - * {@code IllegalStateException} will be thrown. * * @apiNote * For example, {@code Util::getResourceBundle} loads a resource bundle - * on behalf of the caller. It calls this {@code getCallerClass} method - * to find the method calling {@code Util::getResourceBundle} and uses the caller's - * class loader to load the resource bundle. The caller class in this example - * is the {@code MyTool} class. + * on behalf of the caller. It invokes {@code getCallerClass} to identify + * the class whose method called {@code Util::getResourceBundle}. + * Then, it obtains the class loader of that class, and uses + * the class loader to load the resource bundle. The caller class + * in this example is {@code MyTool}. * *

    {@code
          * class Util {
    @@ -517,17 +531,17 @@ public final class StackWalker {
          * }
    * * When the {@code getCallerClass} method is called from a method that - * is the last frame on the stack, + * is the bottom most frame on the stack, * for example, {@code static public void main} method launched by the * {@code java} launcher, or a method invoked from a JNI attached thread, - * {@code IllegalStateException} is thrown. + * {@code IllegalCallerException} is thrown. * * @return {@code Class} object of the caller's caller invoking this method. * * @throws UnsupportedOperationException if this {@code StackWalker} * is not configured with {@link Option#RETAIN_CLASS_REFERENCE * Option.RETAIN_CLASS_REFERENCE}. - * @throws IllegalStateException if there is no caller frame, i.e. + * @throws IllegalCallerException if there is no caller frame, i.e. * when this {@code getCallerClass} method is called from a method * which is the last frame on the stack. */ diff --git a/jdk/src/java.base/share/classes/java/lang/System.java b/jdk/src/java.base/share/classes/java/lang/System.java index 1577e215e35..106ad0fb291 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -1942,13 +1942,12 @@ public final class System { * the application classpath or modulepath. */ private static void initPhase3() { - // Initialize publicLookup early, to avoid bootstrapping circularities - // with security manager using java.lang.invoke infrastructure. - java.lang.invoke.MethodHandles.publicLookup(); - // set security manager String cn = System.getProperty("java.security.manager"); if (cn != null) { + // ensure image reader for java.base is initialized before security manager + Object.class.getResource("module-info.class"); + if (cn.isEmpty() || "default".equals(cn)) { System.setSecurityManager(new SecurityManager()); } else { @@ -2053,6 +2052,9 @@ public final class System { public String fastUUID(long lsb, long msb) { return Long.fastUUID(lsb, msb); } + public void invalidatePackageAccessCache() { + SecurityManager.invalidatePackageAccessCache(); + } }); } } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java index 3f91060ccc8..0675c043185 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java @@ -141,6 +141,18 @@ import static sun.invoke.util.Wrapper.isWrapperType; this.markerInterfaces = markerInterfaces; this.additionalBridges = additionalBridges; + if (samMethodName.isEmpty() || + samMethodName.indexOf('.') >= 0 || + samMethodName.indexOf(';') >= 0 || + samMethodName.indexOf('[') >= 0 || + samMethodName.indexOf('/') >= 0 || + samMethodName.indexOf('<') >= 0 || + samMethodName.indexOf('>') >= 0) { + throw new LambdaConversionException(String.format( + "Method name '%s' is not legal", + samMethodName)); + } + if (!samBase.isInterface()) { throw new LambdaConversionException(String.format( "Functional interface %s is not an interface", @@ -275,25 +287,39 @@ import static sun.invoke.util.Wrapper.isWrapperType; (implKind == MethodHandleInfo.REF_newInvokeSpecial) ? implDefiningClass : implMethodType.returnType(); - Class samReturnType = samMethodType.returnType(); if (!isAdaptableToAsReturn(actualReturnType, expectedType)) { throw new LambdaConversionException( String.format("Type mismatch for lambda return: %s is not convertible to %s", actualReturnType, expectedType)); } - if (!isAdaptableToAsReturnStrict(expectedType, samReturnType)) { - throw new LambdaConversionException( - String.format("Type mismatch for lambda expected return: %s is not convertible to %s", - expectedType, samReturnType)); - } + + // Check descriptors of generated methods + checkDescriptor(samMethodType); for (MethodType bridgeMT : additionalBridges) { - if (!isAdaptableToAsReturnStrict(expectedType, bridgeMT.returnType())) { - throw new LambdaConversionException( - String.format("Type mismatch for lambda expected return: %s is not convertible to %s", - expectedType, bridgeMT.returnType())); + checkDescriptor(bridgeMT); + } + } + + /** Validate that the given descriptor's types are compatible with {@code instantiatedMethodType} **/ + private void checkDescriptor(MethodType descriptor) throws LambdaConversionException { + for (int i = 0; i < instantiatedMethodType.parameterCount(); i++) { + Class instantiatedParamType = instantiatedMethodType.parameterType(i); + Class descriptorParamType = descriptor.parameterType(i); + if (!descriptorParamType.isAssignableFrom(instantiatedParamType)) { + String msg = String.format("Type mismatch for instantiated parameter %d: %s is not a subtype of %s", + i, instantiatedParamType, descriptorParamType); + throw new LambdaConversionException(msg); } } - } + + Class instantiatedReturnType = instantiatedMethodType.returnType(); + Class descriptorReturnType = descriptor.returnType(); + if (!isAdaptableToAsReturnStrict(instantiatedReturnType, descriptorReturnType)) { + String msg = String.format("Type mismatch for lambda expected return: %s is not convertible to %s", + instantiatedReturnType, descriptorReturnType); + throw new LambdaConversionException(msg); + } + } /** * Check type adaptability for parameter types. @@ -345,8 +371,8 @@ import static sun.invoke.util.Wrapper.isWrapperType; || !fromType.equals(void.class) && isAdaptableTo(fromType, toType, false); } private boolean isAdaptableToAsReturnStrict(Class fromType, Class toType) { - if (fromType.equals(void.class)) return toType.equals(void.class); - return isAdaptableTo(fromType, toType, true); + if (fromType.equals(void.class) || toType.equals(void.class)) return fromType.equals(toType); + else return isAdaptableTo(fromType, toType, true); } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 16a9e8a941d..98f02d0f19f 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -25,8 +25,6 @@ package java.lang.invoke; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.vm.annotation.ForceInline; @@ -111,13 +109,17 @@ public class MethodHandles { /** * Returns a {@link Lookup lookup object} which is trusted minimally. - * It can only be used to create method handles to public members in + * The lookup has the {@code PUBLIC} and {@code UNCONDITIONAL} modes. + * It can only be used to create method handles to public members of * public classes in packages that are exported unconditionally. *

    - * For now, the {@linkplain Lookup#lookupClass lookup class} of this lookup - * object is in an unnamed module. - * Consequently, the lookup context of this lookup object will be the bootstrap - * class loader, which means it cannot find user classes. + * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} + * of this lookup object will be {@link java.lang.Object}. + * + * @apiNote The use of Object is conventional, and because the lookup modes are + * limited, there is no special access provided to the internals of Object, its package + * or its module. Consequently, the lookup context of this lookup object will be the + * bootstrap class loader, which means it cannot find user classes. * *

    * Discussion: @@ -129,17 +131,12 @@ public class MethodHandles { * Also, it cannot access * caller sensitive methods. * @return a lookup object which is trusted minimally + * + * @revised 9 + * @spec JPMS */ public static Lookup publicLookup() { - // During VM startup then only classes in the java.base module can be - // loaded and linked. This is because java.base exports aren't setup until - // the module system is initialized, hence types in the unnamed module - // (or any named module) can't link to java/lang/Object. - if (!jdk.internal.misc.VM.isModuleSystemInited()) { - return new Lookup(Object.class, Lookup.PUBLIC); - } else { - return LookupHelper.PUBLIC_LOOKUP; - } + return Lookup.PUBLIC_LOOKUP; } /** @@ -172,6 +169,7 @@ public class MethodHandles { * @throws IllegalAccessException if the access check specified above fails * @throws SecurityException if denied by the security manager * @since 9 + * @spec JPMS * @see Lookup#dropLookupMode */ public static Lookup privateLookupIn(Class targetClass, Lookup lookup) throws IllegalAccessException { @@ -183,11 +181,11 @@ public class MethodHandles { throw new IllegalArgumentException(targetClass + " is an array class"); Module targetModule = targetClass.getModule(); Module callerModule = lookup.lookupClass().getModule(); - if (callerModule != targetModule && targetModule.isNamed()) { - if (!callerModule.canRead(targetModule)) - throw new IllegalAccessException(callerModule + " does not read " + targetModule); + if (!callerModule.canRead(targetModule)) + throw new IllegalAccessException(callerModule + " does not read " + targetModule); + if (targetModule.isNamed()) { String pn = targetClass.getPackageName(); - assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module"; + assert pn.length() > 0 : "unnamed package cannot be in named module"; if (!targetModule.isOpen(pn, callerModule)) throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule); } @@ -601,6 +599,8 @@ public class MethodHandles { * so that there can be a secure foundation for lookups. * Nearly all other methods in the JSR 292 API rely on lookup * objects to check access requests. + * + * @revised 9 */ public static final class Lookup { @@ -647,15 +647,33 @@ public class MethodHandles { * lookup class and public types in packages exported by other modules * to the module of the lookup class. * @since 9 + * @spec JPMS */ public static final int MODULE = PACKAGE << 1; - private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE); + /** A single-bit mask representing {@code unconditional} access + * which may contribute to the result of {@link #lookupModes lookupModes}. + * The value is {@code 0x20}, which does not correspond meaningfully to + * any particular {@linkplain java.lang.reflect.Modifier modifier bit}. + * A {@code Lookup} with this lookup mode assumes {@linkplain + * java.lang.reflect.Module#canRead(java.lang.reflect.Module) readability}. + * In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup} + * with this lookup mode can access all public members of public types + * of all modules where the type is in a package that is {@link + * java.lang.reflect.Module#isExported(String) exported unconditionally}. + * @since 9 + * @spec JPMS + * @see #publicLookup() + */ + public static final int UNCONDITIONAL = PACKAGE << 2; + + private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE | UNCONDITIONAL); + private static final int FULL_POWER_MODES = (ALL_MODES & ~UNCONDITIONAL); private static final int TRUSTED = -1; private static int fixmods(int mods) { - mods &= (ALL_MODES - PACKAGE - MODULE); - return (mods != 0) ? mods : (PACKAGE | MODULE); + mods &= (ALL_MODES - PACKAGE - MODULE - UNCONDITIONAL); + return (mods != 0) ? mods : (PACKAGE | MODULE | UNCONDITIONAL); } /** Tells which class is performing the lookup. It is this class against @@ -682,13 +700,14 @@ public class MethodHandles { * {@linkplain #PRIVATE PRIVATE (0x02)}, * {@linkplain #PROTECTED PROTECTED (0x04)}, * {@linkplain #PACKAGE PACKAGE (0x08)}, - * and {@linkplain #MODULE MODULE (0x10)}. + * {@linkplain #MODULE MODULE (0x10)}, + * and {@linkplain #UNCONDITIONAL UNCONDITIONAL (0x20)}. *

    * A freshly-created lookup object - * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class} - * has all possible bits set, since the caller class can access all its own members, - * all public types in the caller's module, and all public types in packages exported - * by other modules to the caller's module. + * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class} has + * all possible bits set, except {@code UNCONDITIONAL}. The lookup can be used to + * access all members of the caller's class, all public types in the caller's module, + * and all public types in packages exported by other modules to the caller's module. * A lookup object on a new lookup class * {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object} * may have some mode bits set to zero. @@ -701,6 +720,9 @@ public class MethodHandles { * @return the lookup modes, which limit the kinds of access performed by this lookup object * @see #in * @see #dropLookupMode + * + * @revised 9 + * @spec JPMS */ public int lookupModes() { return allowedModes & ALL_MODES; @@ -712,9 +734,9 @@ public class MethodHandles { * which in turn is called by a method not in this package. */ Lookup(Class lookupClass) { - this(lookupClass, ALL_MODES); + this(lookupClass, FULL_POWER_MODES); // make sure we haven't accidentally picked up a privileged class: - checkUnprivilegedlookupClass(lookupClass, ALL_MODES); + checkUnprivilegedlookupClass(lookupClass, FULL_POWER_MODES); } private Lookup(Class lookupClass, int allowedModes) { @@ -730,19 +752,20 @@ public class MethodHandles { * However, the resulting {@code Lookup} object is guaranteed * to have no more access capabilities than the original. * In particular, access capabilities can be lost as follows:

      - *
    • If the lookup class for this {@code Lookup} is not in a named module, - * and the new lookup class is in a named module {@code M}, then no members in - * {@code M}'s non-exported packages will be accessible. - *
    • If the lookup for this {@code Lookup} is in a named module, and the - * new lookup class is in a different module {@code M}, then no members, not even - * public members in {@code M}'s exported packages, will be accessible. - *
    • If the new lookup class differs from the old one, - * protected members will not be accessible by virtue of inheritance. - * (Protected members may continue to be accessible because of package sharing.) + *
    • If the old lookup class is in a {@link Module#isNamed() named} module, and + * the new lookup class is in a different module {@code M}, then no members, not + * even public members in {@code M}'s exported packages, will be accessible. + * The exception to this is when this lookup is {@link #publicLookup() + * publicLookup}, in which case {@code PUBLIC} access is not lost. + *
    • If the old lookup class is in an unnamed module, and the new lookup class + * is a different module then {@link #MODULE MODULE} access is lost. + *
    • If the new lookup class differs from the old one then {@code UNCONDITIONAL} is lost. *
    • If the new lookup class is in a different package * than the old one, protected and default (package) members will not be accessible. *
    • If the new lookup class is not within the same package member - * as the old one, private members will not be accessible. + * as the old one, private members will not be accessible, and protected members + * will not be accessible by virtue of inheritance. + * (Protected members may continue to be accessible because of package sharing.) *
    • If the new lookup class is not accessible to the old lookup class, * then no members, not even public members, will be accessible. * (In all other cases, public members will continue to be accessible.) @@ -757,32 +780,34 @@ public class MethodHandles { * @return a lookup object which reports the desired lookup class, or the same object * if there is no change * @throws NullPointerException if the argument is null + * + * @revised 9 + * @spec JPMS */ public Lookup in(Class requestedLookupClass) { Objects.requireNonNull(requestedLookupClass); if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all - return new Lookup(requestedLookupClass, ALL_MODES); + return new Lookup(requestedLookupClass, FULL_POWER_MODES); if (requestedLookupClass == this.lookupClass) return this; // keep same capabilities - - int newModes = (allowedModes & (ALL_MODES & ~PROTECTED)); + int newModes = (allowedModes & FULL_POWER_MODES); if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) { - // Allowed to teleport from an unnamed to a named module but resulting - // Lookup has no access to module private members - if (this.lookupClass.getModule().isNamed()) { + // Need to drop all access when teleporting from a named module to another + // module. The exception is publicLookup where PUBLIC is not lost. + if (this.lookupClass.getModule().isNamed() + && (this.allowedModes & UNCONDITIONAL) == 0) newModes = 0; - } else { - newModes &= ~MODULE; - } + else + newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED); } if ((newModes & PACKAGE) != 0 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) { - newModes &= ~(PACKAGE|PRIVATE); + newModes &= ~(PACKAGE|PRIVATE|PROTECTED); } // Allow nestmate lookups to be created without special privilege: if ((newModes & PRIVATE) != 0 && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) { - newModes &= ~PRIVATE; + newModes &= ~(PRIVATE|PROTECTED); } if ((newModes & PUBLIC) != 0 && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) { @@ -801,28 +826,29 @@ public class MethodHandles { * finds members, but with a lookup mode that has lost the given lookup mode. * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}. - * {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup - * mode will never have this access capability. When dropping {@code PACKAGE} - * then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE} - * access. When dropping {@code MODULE} then the resulting lookup will not - * have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code - * PUBLIC} is dropped then the resulting lookup has no access. + * {@link #PROTECTED PROTECTED} and {@link #UNCONDITIONAL UNCONDITIONAL} are always + * dropped and so the resulting lookup mode will never have these access capabilities. + * When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE} + * or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will + * not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC} + * is dropped then the resulting lookup has no access. * @param modeToDrop the lookup mode to drop * @return a lookup object which lacks the indicated mode, or the same object if there is no change * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC}, - * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE} - * @since 9 + * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED}, {@code PRIVATE} or {@code UNCONDITIONAL} * @see MethodHandles#privateLookupIn + * @since 9 */ public Lookup dropLookupMode(int modeToDrop) { int oldModes = lookupModes(); - int newModes = oldModes & ~(modeToDrop | PROTECTED); + int newModes = oldModes & ~(modeToDrop | PROTECTED | UNCONDITIONAL); switch (modeToDrop) { case PUBLIC: newModes &= ~(ALL_MODES); break; case MODULE: newModes &= ~(PACKAGE | PRIVATE); break; case PACKAGE: newModes &= ~(PRIVATE); break; case PROTECTED: - case PRIVATE: break; + case PRIVATE: + case UNCONDITIONAL: break; default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop"); } if (newModes == oldModes) return this; // return self if no change @@ -835,6 +861,12 @@ public class MethodHandles { /** Package-private version of lookup which is trusted. */ static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED); + /** Version of lookup which is trusted minimally. + * It can only be used to create method handles to publicly accessible + * members in packages that are exported unconditionally. + */ + static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, (PUBLIC|UNCONDITIONAL)); + private static void checkUnprivilegedlookupClass(Class lookupClass, int allowedModes) { String name = lookupClass.getName(); if (name.startsWith("java.lang.invoke.")) @@ -845,7 +877,7 @@ public class MethodHandles { // TODO replace with a more formal and less fragile mechanism // that does not bluntly restrict classes under packages within // java.base from looking up MethodHandles or VarHandles. - if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) { + if (allowedModes == FULL_POWER_MODES && lookupClass.getClassLoader() == null) { if ((name.startsWith("java.") && !name.equals("java.lang.Thread") && !name.startsWith("java.util.concurrent.")) || @@ -866,6 +898,7 @@ public class MethodHandles { *
        *
      • If no access is allowed, the suffix is "/noaccess". *
      • If only public access to types in exported packages is allowed, the suffix is "/public". + *
      • If only public access and unconditional access are allowed, the suffix is "/publicLookup". *
      • If only public and module access are allowed, the suffix is "/module". *
      • If only public, module and package access are allowed, the suffix is "/package". *
      • If only public, module, package, and private access are allowed, the suffix is "/private". @@ -884,6 +917,9 @@ public class MethodHandles { * because it requires a direct subclass relationship between * caller and callee.) * @see #in + * + * @revised 9 + * @spec JPMS */ @Override public String toString() { @@ -893,13 +929,15 @@ public class MethodHandles { return cname + "/noaccess"; case PUBLIC: return cname + "/public"; + case PUBLIC|UNCONDITIONAL: + return cname + "/publicLookup"; case PUBLIC|MODULE: return cname + "/module"; case PUBLIC|MODULE|PACKAGE: return cname + "/package"; - case ALL_MODES & ~PROTECTED: + case FULL_POWER_MODES & ~PROTECTED: return cname + "/private"; - case ALL_MODES: + case FULL_POWER_MODES: return cname; case TRUSTED: return "/trusted"; // internal only; not exported @@ -1580,6 +1618,7 @@ return mh1; if (refKind == REF_invokeSpecial) refKind = REF_invokeVirtual; assert(method.isMethod()); + @SuppressWarnings("deprecation") Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); } @@ -1662,6 +1701,7 @@ return mh1; public MethodHandle unreflectConstructor(Constructor c) throws IllegalAccessException { MemberName ctor = new MemberName(c); assert(ctor.isConstructor()); + @SuppressWarnings("deprecation") Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this; return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor); } @@ -1692,6 +1732,7 @@ return mh1; assert(isSetter ? MethodHandleNatives.refKindIsSetter(field.getReferenceKind()) : MethodHandleNatives.refKindIsGetter(field.getReferenceKind())); + @SuppressWarnings("deprecation") Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this; return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field); } @@ -2033,9 +2074,9 @@ return mh1; (defc == refc || Modifier.isPublic(refc.getModifiers()))); if (!classOK && (allowedModes & PACKAGE) != 0) { - classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) && + classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), FULL_POWER_MODES) && (defc == refc || - VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES))); + VerifyAccess.isClassAccessible(refc, lookupClass(), FULL_POWER_MODES))); } if (!classOK) return "class is not public"; @@ -2347,53 +2388,6 @@ return mh1; static ConcurrentHashMap LOOKASIDE_TABLE = new ConcurrentHashMap<>(); } - /** - * Helper class used to lazily create PUBLIC_LOOKUP with a lookup class - * in an unnamed module. - * - * @see Lookup#publicLookup - */ - private static class LookupHelper { - private static final String UNNAMED = "Unnamed"; - private static final String OBJECT = "java/lang/Object"; - - private static Class createClass() { - try { - ClassWriter cw = new ClassWriter(0); - cw.visit(Opcodes.V1_8, - Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, - UNNAMED, - null, - OBJECT, - null); - cw.visitSource(UNNAMED, null); - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - ClassLoader loader = new ClassLoader(null) { - @Override - protected Class findClass(String cn) throws ClassNotFoundException { - if (cn.equals(UNNAMED)) - return super.defineClass(UNNAMED, bytes, 0, bytes.length); - throw new ClassNotFoundException(cn); - } - }; - return loader.loadClass(UNNAMED); - } catch (Exception e) { - throw new InternalError(e); - } - } - - private static final Class PUBLIC_LOOKUP_CLASS = createClass(); - - /** - * Lookup that is trusted minimally. It can only be used to create - * method handles to publicly accessible members in exported packages. - * - * @see MethodHandles#publicLookup - */ - static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_LOOKUP_CLASS, Lookup.PUBLIC); - } - /** * Produces a method handle constructing arrays of a desired type. * The return type of the method handle will be the array type. diff --git a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java index 9753569374d..6203b1277ff 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java +++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,126 +42,48 @@ import java.util.stream.Collectors; import java.util.stream.Stream; /** - * The configuration that is the result of resolution or resolution with - * service binding. + * A configuration that is the result of + * resolution or resolution with + * service binding. * - *

        Resolution

        + *

        A configuration encapsulates the readability graph that is the + * output of resolution. A readability graph is a directed graph where the nodes + * are of type {@link ResolvedModule} and the edges represent the readability + * amongst the modules. {@code Configuration} defines the {@link #modules() + * modules()} method to get the set of resolved modules in the graph. {@code + * ResolvedModule} defines the {@link ResolvedModule#reads() reads()} method to + * get the set of modules that a resolved module reads. The modules that are + * read may be in the same configuration or may be in {@link #parents() parent} + * configurations.

        * - *

        Resolution is the process of computing the transitive closure of a set - * of root modules over a set of observable modules by resolving the - * dependences expressed by {@code requires} clauses. + *

        Configuration defines the {@link #resolve(ModuleFinder,List,ModuleFinder,Collection) + * resolve} method to resolve a collection of root modules, and the {@link + * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) resolveAndBind} + * method to do resolution with service binding. There are instance and + * static variants of both methods. The instance methods create a configuration + * with the receiver as the parent configuration. The static methods are for + * more advanced cases where there can be more than one parent configuration.

        * - * The dependence graph is augmented with edges that take account of - * implicitly declared dependences ({@code requires transitive}) to create a - * readability graph. A {@code Configuration} encapsulates the - * resulting graph of {@link ResolvedModule resolved modules}. - * - *

        Suppose we have the following observable modules:

        - *
         {@code
        - *     module m1 { requires m2; }
        - *     module m2 { requires transitive m3; }
        - *     module m3 { }
        - *     module m4 { }
        - * } 
        - * - *

        If the module {@code m1} is resolved then the resulting configuration - * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in - * its readability graph are:

        - *
         {@code
        - *     m1 --> m2  (meaning m1 reads m2)
        - *     m1 --> m3
        - *     m2 --> m3
        - * } 
        - * - *

        Resolution is an additive process. When computing the transitive closure - * then the dependence relation may include dependences on modules in parent - * configurations. The result is a relative configuration that is - * relative to one or more parent configurations and where the readability graph - * may have edges from modules in the configuration to modules in parent - * configurations. - * - *

        - * - *

        Suppose we have the following observable modules:

        - *
         {@code
        - *     module m1 { requires m2; requires java.xml; }
        - *     module m2 { }
        - * } 
        - * - *

        If module {@code m1} is resolved with the configuration for the {@link - * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting - * configuration contains two modules ({@code m1}, {@code m2}). The edges in - * its readability graph are: - *

         {@code
        - *     m1 --> m2
        - *     m1 --> java.xml
        - * } 
        - * where module {@code java.xml} is in the parent configuration. For - * simplicity, this example omits the implicitly declared dependence on the - * {@code java.base} module. - * - * - *

        {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special - * treatment during resolution. Each automatic module is resolved so that it - * reads all other modules in the configuration and all parent configurations. - * Each automatic module is also resolved as if it {@code requires transitive} - * all other automatic modules in the configuration (and all automatic modules - * in parent configurations).

        - - *

        Service binding

        - * - *

        Service binding is the process of augmenting a graph of resolved modules - * from the set of observable modules induced by the service-use dependence - * ({@code uses} and {@code provides} clauses). Any module that was not - * previously in the graph requires resolution to compute its transitive - * closure. Service binding is an iterative process in that adding a module - * that satisfies some service-use dependence may introduce new service-use - * dependences.

        - * - *

        Suppose we have the following observable modules:

        - *
         {@code
        - *     module m1 { exports p; uses p.S; }
        - *     module m2 { requires m1; provides p.S with p2.S2; }
        - *     module m3 { requires m1; requires m4; provides p.S with p3.S3; }
        - *     module m4 { }
        - * } 
        - * - *

        If the module {@code m1} is resolved then the resulting graph of modules - * has one module ({@code m1}). If the graph is augmented with modules induced - * by the service-use dependence relation then the configuration will contain - * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in - * its readability graph are:

        - *
         {@code
        - *     m2 --> m1
        - *     m3 --> m1
        - *     m3 --> m4
        - * } 
        - *

        The edges in the conceptual service-use graph are:

        - *
         {@code
        - *     m1 --> m2  (meaning m1 uses a service that is provided by m2)
        - *     m1 --> m3
        - * } 
        - * - *

        If this configuration is instantiated as a {@code Layer}, and if code in - * module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to - * iterate over implementations of {@code p.S.class}, then it will iterate over - * an instance of {@code p2.S2} and {@code p3.S3}.

        + *

        Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual + * machine is created from a configuration. The configuration for the {@link + * java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code + * Layer.boot().configuration()}. The configuration for the boot layer will + * often be the parent when creating new configurations.

        * *

        Example

        * - *

        The following example uses the {@code resolveRequires} method to resolve - * a module named myapp with the configuration for the boot layer as - * the parent configuration. It prints the name of each resolved module and - * the names of the modules that each module reads.

        + *

        The following example uses the {@link + * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a + * module named myapp with the configuration for the boot layer as the + * parent configuration. It prints the name of each resolved module and the + * names of the modules that each module reads.

        * *
        {@code
          *    ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
          *
          *    Configuration parent = Layer.boot().configuration();
          *
        - *    Configuration cf = parent.resolveRequires(finder,
        - *                                              ModuleFinder.of(),
        - *                                              Set.of("myapp"));
        + *    Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp"));
          *    cf.modules().forEach(m -> {
          *        System.out.format("%s -> %s%n",
          *            m.name(),
        @@ -172,6 +94,7 @@ import java.util.stream.Stream;
          * }
        * * @since 9 + * @spec JPMS * @see java.lang.reflect.Layer */ public final class Configuration { @@ -186,11 +109,23 @@ public final class Configuration { private final Set modules; private final Map nameToModule; + // module constraints on target + private final String osName; + private final String osArch; + private final String osVersion; + + String osName() { return osName; } + String osArch() { return osArch; } + String osVersion() { return osVersion; } + private Configuration() { this.parents = Collections.emptyList(); this.graph = Collections.emptyMap(); this.modules = Collections.emptySet(); this.nameToModule = Collections.emptyMap(); + this.osName = null; + this.osArch = null; + this.osVersion = null; } private Configuration(List parents, @@ -214,27 +149,30 @@ public final class Configuration { this.graph = g; this.modules = Set.of(moduleArray); this.nameToModule = Map.ofEntries(nameEntries); - } + this.osName = resolver.osName(); + this.osArch = resolver.osArch(); + this.osVersion = resolver.osVersion(); + } /** * Resolves a collection of root modules, with this configuration as its * parent, to create a new configuration. This method works exactly as * specified by the static {@link - * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires} + * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve} * method when invoked with this configuration as the parent. In other words, * if this configuration is {@code cf} then this method is equivalent to * invoking: *
         {@code
        -     *     Configuration.resolveRequires(before, List.of(cf), after, roots);
        +     *     Configuration.resolve(before, List.of(cf), after, roots);
              * }
        * * @param before * The before module finder to find modules * @param after - * The after module finder to locate modules when a - * module cannot be located by the {@code before} module finder - * and the module is not in this configuration + * The after module finder to locate modules when not + * located by the {@code before} module finder or in parent + * configurations * @param roots * The possibly-empty collection of module names of the modules * to resolve @@ -242,16 +180,20 @@ public final class Configuration { * @return The configuration that is the result of resolving the given * root modules * + * @throws FindException + * If resolution fails for any of the observability-related reasons + * specified by the static {@code resolve} method * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If any of the post-resolution consistency checks specified by + * the static {@code resolve} method fail * @throws SecurityException * If locating a module is denied by the security manager */ - public Configuration resolveRequires(ModuleFinder before, - ModuleFinder after, - Collection roots) + public Configuration resolve(ModuleFinder before, + ModuleFinder after, + Collection roots) { - return resolveRequires(before, List.of(this), after, roots); + return resolve(before, List.of(this), after, roots); } @@ -259,12 +201,12 @@ public final class Configuration { * Resolves a collection of root modules, with service binding, and with * this configuration as its parent, to create a new configuration. * This method works exactly as specified by the static {@link - * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection) - * resolveRequiresAndUses} method when invoked with this configuration + * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) + * resolveAndBind} method when invoked with this configuration * as the parent. In other words, if this configuration is {@code cf} then * this method is equivalent to invoking: *
         {@code
        -     *     Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
        +     *     Configuration.resolveAndBind(before, List.of(cf), after, roots);
              * }
        * * @@ -272,25 +214,29 @@ public final class Configuration { * The before module finder to find modules * @param after * The after module finder to locate modules when not - * located by the {@code before} module finder and this - * configuration + * located by the {@code before} module finder or in parent + * configurations * @param roots * The possibly-empty collection of module names of the modules * to resolve * - * @return The configuration that is the result of resolving the given - * root modules + * @return The configuration that is the result of resolving, with service + * binding, the given root modules * + * @throws FindException + * If resolution fails for any of the observability-related reasons + * specified by the static {@code resolve} method * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If any of the post-resolution consistency checks specified by + * the static {@code resolve} method fail * @throws SecurityException * If locating a module is denied by the security manager */ - public Configuration resolveRequiresAndUses(ModuleFinder before, - ModuleFinder after, - Collection roots) + public Configuration resolveAndBind(ModuleFinder before, + ModuleFinder after, + Collection roots) { - return resolveRequiresAndUses(before, List.of(this), after, roots); + return resolveAndBind(before, List.of(this), after, roots); } @@ -301,14 +247,14 @@ public final class Configuration { * * This method is used to create the configuration for the boot layer. */ - static Configuration resolveRequiresAndUses(ModuleFinder finder, - Collection roots, - boolean check, - PrintStream traceOutput) + static Configuration resolveAndBind(ModuleFinder finder, + Collection roots, + boolean check, + PrintStream traceOutput) { List parents = List.of(empty()); Resolver resolver = new Resolver(finder, parents, ModuleFinder.of(), traceOutput); - resolver.resolveRequires(roots).resolveUses(); + resolver.resolve(roots).bind(); return new Configuration(parents, resolver, check); } @@ -328,11 +274,11 @@ public final class Configuration { * *

        When all modules have been resolved then the resulting dependency * graph is checked to ensure that it does not contain cycles. A - * readability graph is constructed and in conjunction with the module + * readability graph is constructed, and in conjunction with the module * exports and service use, checked for consistency.

        * - *

        Resolution and the (post-resolution) consistency checks may fail for - * following reasons:

        + *

        Resolution may fail with {@code FindException} for the following + * observability-related reasons:

        * *
          *
        • A root module, or a direct or transitive dependency, is not @@ -343,6 +289,20 @@ public final class Configuration { * descriptor ({@code module-info.class}) or two versions of the same * module are found in the same directory.

        • * + *
        • A module with the required name is found but the module + * requires a different {@link ModuleDescriptor#osName() operating + * system}, {@link ModuleDescriptor#osArch() architecture}, or {@link + * ModuleDescriptor#osVersion() version} to other modules that have + * been resolved for the new configuration or modules in the parent + * configurations.

        • + * + *
        + * + *

        Post-resolution consistency checks may fail with {@code + * ResolutionException} for the following reasons:

        + * + *
          + * *
        • A cycle is detected, say where module {@code m1} requires * module {@code m2} and {@code m2} requires {@code m1}.

        • * @@ -356,21 +316,12 @@ public final class Configuration { * module {@code M} nor exported to {@code M} by any module that * {@code M} reads.

          * - *
        • A module {@code M} declares that it - * "{@code provides ... with q.T}" but package {@code q} is not in - * module {@code M}.

        • - * - *
        • Two or more modules in the configuration are specific to - * different {@link ModuleDescriptor#osName() operating systems}, - * {@link ModuleDescriptor#osArch() architectures}, or {@link - * ModuleDescriptor#osVersion() versions}.

        • - * - *
        • Other implementation specific checks, for example referential - * integrity checks to ensure that different versions of tighly coupled - * modules cannot be combined in the same configuration.

        • - * *
        * + * @implNote In the implementation then observability of modules may depend + * on referential integrity checks that ensure different builds of tightly + * coupled modules are not combined in the same configuration. + * * @param before * The before module finder to find modules * @param parents @@ -386,17 +337,22 @@ public final class Configuration { * @return The configuration that is the result of resolving the given * root modules * + * @throws FindException + * If resolution fails for an observability-related reason * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If a post-resolution consistency checks fails * @throws IllegalArgumentException - * If the list of parents is empty + * If the list of parents is empty, or the list has two or more + * parents with modules for different target operating systems, + * architectures, or versions + * * @throws SecurityException * If locating a module is denied by the security manager */ - public static Configuration resolveRequires(ModuleFinder before, - List parents, - ModuleFinder after, - Collection roots) + public static Configuration resolve(ModuleFinder before, + List parents, + ModuleFinder after, + Collection roots) { Objects.requireNonNull(before); Objects.requireNonNull(after); @@ -407,7 +363,7 @@ public final class Configuration { throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); - resolver.resolveRequires(roots); + resolver.resolve(roots); return new Configuration(parentList, resolver, true); } @@ -417,24 +373,24 @@ public final class Configuration { * configuration. * *

        This method works exactly as specified by {@link - * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) - * resolveRequires} except that the graph of resolved modules is augmented + * #resolve(ModuleFinder,List,ModuleFinder,Collection) + * resolve} except that the graph of resolved modules is augmented * with modules induced by the service-use dependence relation.

        * *

        More specifically, the root modules are resolved as if by calling - * {@code resolveRequires}. The resolved modules, and all modules in the + * {@code resolve}. The resolved modules, and all modules in the * parent configurations, with {@link ModuleDescriptor#uses() service * dependences} are then examined. All modules found by the given module * finders that {@link ModuleDescriptor#provides() provide} an * implementation of one or more of the service types are added to the * module graph and then resolved as if by calling the {@code - * resolveRequires} method. Adding modules to the module graph may - * introduce new service-use dependences and so the process works - * iteratively until no more modules are added.

        + * resolve} method. Adding modules to the module graph may introduce new + * service-use dependences and so the process works iteratively until no + * more modules are added.

        * - *

        As service binding involves resolution then it may fail with {@link - * ResolutionException} for exactly the same reasons specified in - * {@code resolveRequires}.

        + *

        As service binding involves resolution then it may fail with {@code + * FindException} or {@code ResolutionException} for exactly the same + * reasons specified in {@code resolve}.

        * * @param before * The before module finder to find modules @@ -448,20 +404,26 @@ public final class Configuration { * The possibly-empty collection of module names of the modules * to resolve * - * @return The configuration that is the result of resolving the given - * root modules + * @return The configuration that is the result of resolving, with service + * binding, the given root modules * + * @throws FindException + * If resolution fails for any of the observability-related reasons + * specified by the static {@code resolve} method * @throws ResolutionException - * If resolution or the post-resolution checks fail + * If any of the post-resolution consistency checks specified by + * the static {@code resolve} method fail * @throws IllegalArgumentException - * If the list of parents is empty + * If the list of parents is empty, or the list has two or more + * parents with modules for different target operating systems, + * architectures, or versions * @throws SecurityException * If locating a module is denied by the security manager */ - public static Configuration resolveRequiresAndUses(ModuleFinder before, - List parents, - ModuleFinder after, - Collection roots) + public static Configuration resolveAndBind(ModuleFinder before, + List parents, + ModuleFinder after, + Collection roots) { Objects.requireNonNull(before); Objects.requireNonNull(after); @@ -472,7 +434,7 @@ public final class Configuration { throw new IllegalArgumentException("'parents' is empty"); Resolver resolver = new Resolver(before, parentList, after, null); - resolver.resolveRequires(roots).resolveUses(); + resolver.resolve(roots).bind(); return new Configuration(parentList, resolver, true); } diff --git a/jdk/src/java.base/share/classes/java/lang/module/FindException.java b/jdk/src/java.base/share/classes/java/lang/module/FindException.java index d76f2935e7e..411959eb418 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/FindException.java +++ b/jdk/src/java.base/share/classes/java/lang/module/FindException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,10 +26,14 @@ package java.lang.module; /** - * Thrown by module finders when finding a module fails. + * Thrown by a {@link ModuleFinder ModuleFinder} when an error occurs finding + * a module. Also thrown by {@link + * Configuration#resolve(ModuleFinder,java.util.List,ModuleFinder,java.util.Collection) + * Configuration.resolve} when resolution fails for observability-related + * reasons. * - * @see ModuleFinder * @since 9 + * @spec JPMS */ public class FindException extends RuntimeException { diff --git a/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java b/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java index 981f23a5189..3e306886fb2 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java +++ b/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java @@ -31,6 +31,7 @@ package java.lang.module; * * @see ModuleDescriptor#read * @since 9 + * @spec JPMS */ public class InvalidModuleDescriptorException extends RuntimeException { private static final long serialVersionUID = 4863390386809347380L; diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index b10d986ade9..6c05e821026 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -56,29 +57,83 @@ import jdk.internal.module.ModuleInfo; /** * A module descriptor. * - *

        A {@code ModuleDescriptor} is typically created from the binary form - * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder} - * class can be used to create a {@code ModuleDescriptor} from its components. - * The {@link #module module}, {@link #openModule openModule}, and {@link - * #automaticModule automaticModule} methods create builders for building - * different kinds of modules.

        + *

        A module descriptor describes a named module and defines methods to + * obtain each of its components. The module descriptor for a named module + * in the Java virtual machine is obtained by invoking the {@link + * java.lang.reflect.Module Module}'s {@link java.lang.reflect.Module#getDescriptor + * getDescriptor} method. Module descriptors can also be created using the + * {@link ModuleDescriptor.Builder} class or by reading the binary form of a + * module declaration ({@code module-info.class}) using the {@link + * #read(InputStream,Supplier) read} methods defined here.

        + * + *

        A module descriptor describes a normal, open, or automatic + * module. Normal modules and open modules describe their {@link + * #requires() dependences}, {@link #exports() exported-packages}, the services + * that they {@link #uses() use} or {@link #provides() provide}, and other + * components. Normal modules may {@link #opens() open} specific + * packages. The module descriptor for an open modules does not declare any + * open packages (its {@code opens} method returns an empty set) but when + * instantiated in the Java virtual machine then it is treated as if all + * packages are open. The module descriptor for an automatic module does not + * declare any dependences (except for the mandatory dependency on {@code + * java.base}), and does not declare any exported or open packages. Automatic + * module receive special treatment during resolution so that they read all + * other modules in the configuration. When an automatic module is instantiated + * in the Java virtual machine then it reads every unnamed module and is + * treated as if all packages are exported and open.

        * *

        {@code ModuleDescriptor} objects are immutable and safe for use by * multiple concurrent threads.

        * - * @since 9 * @see java.lang.reflect.Module + * @since 9 + * @spec JPMS */ public class ModuleDescriptor implements Comparable { + /** + * A modifier on a module. + * + * @see ModuleDescriptor#modifiers() + * @since 9 + */ + public static enum Modifier { + /** + * An open module. An open module does not declare any open packages + * but the resulting module is treated as if all packages are open. + */ + OPEN, + + /** + * An automatic module. An automatic module is treated as if it exports + * and opens all packages. + * + * @apiNote This modifier does not correspond to a module flag in the + * binary form of a module declaration ({@code module-info.class}). + */ + AUTOMATIC, + + /** + * The module was not explicitly or implicitly declared. + */ + SYNTHETIC, + + /** + * The module was implicitly declared. + */ + MANDATED; + } + + /** *

        A dependence upon a module

        * * @see ModuleDescriptor#requires() * @since 9 + * @spec JPMS */ public final static class Requires @@ -88,7 +143,9 @@ public class ModuleDescriptor /** * A modifier on a module dependence. * + * @see Requires#modifiers() * @since 9 + * @spec JPMS */ public static enum Modifier { @@ -171,14 +228,18 @@ public class ModuleDescriptor * Compares this module dependence to another. * *

        Two {@code Requires} objects are compared by comparing their - * module name lexicographically. Where the module names are equal then - * the sets of modifiers are compared based on a value computed from the - * ordinal of each modifier. Where the module names are equal and the - * set of modifiers are equal then the version of the modules recorded - * at compile-time are compared. When comparing the versions recorded - * at compile-time then a dependence that has a recorded version is - * considered to succeed a dependence that does not have a recorded - * version.

        + * module names lexicographically. Where the module names are equal + * then the sets of modifiers are compared in the same way that + * module modifiers are compared (see {@link ModuleDescriptor#compareTo + * ModuleDescriptor.compareTo}). Where the module names are equal and + * the set of modifiers are equal then the version of the modules + * recorded at compile-time are compared. When comparing the versions + * recorded at compile-time then a dependence that has a recorded + * version is considered to succeed a dependence that does not have a + * recorded version.

        + * + * @param that + * The module dependence to compare * * @return A negative integer, zero, or a positive integer if this module * dependence is less than, equal to, or greater than the given @@ -186,39 +247,22 @@ public class ModuleDescriptor */ @Override public int compareTo(Requires that) { + if (this == that) return 0; + int c = this.name().compareTo(that.name()); - if (c != 0) - return c; + if (c != 0) return c; // modifiers - c = Long.compare(this.modsValue(), that.modsValue()); - if (c != 0) - return c; + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) return c; // compiledVersion - if (this.compiledVersion != null) { - if (that.compiledVersion != null) - c = this.compiledVersion.compareTo(that.compiledVersion); - else - c = 1; - } else { - if (that.compiledVersion != null) - c = -1; - } + c = compare(this.compiledVersion, that.compiledVersion); + if (c != 0) return c; - return c; - } - - /** - * Return a value for the modifiers to allow sets of modifiers to be - * compared. - */ - private long modsValue() { - long value = 0; - for (Modifier m : mods) { - value += 1 << m.ordinal(); - } - return value; + return 0; } /** @@ -266,9 +310,9 @@ public class ModuleDescriptor } /** - * Returns a string describing module dependence. + * Returns a string describing this module dependence. * - * @return A string describing module dependence + * @return A string describing this module dependence */ @Override public String toString() { @@ -285,18 +329,23 @@ public class ModuleDescriptor /** - *

        A module export, may be qualified or unqualified.

        + *

        A package exported by a module, may be qualified or unqualified.

        * * @see ModuleDescriptor#exports() * @since 9 + * @spec JPMS */ - public final static class Exports { + public final static class Exports + implements Comparable + { /** - * A modifier on a module export. + * A modifier on an exported package. * + * @see Exports#modifiers() * @since 9 + * @spec JPMS */ public static enum Modifier { @@ -380,6 +429,52 @@ public class ModuleDescriptor return targets; } + /** + * Compares this module export to another. + * + *

        Two {@code Exports} objects are compared by comparing the package + * names lexicographically. Where the packages names are equal then the + * sets of modifiers are compared in the same way that module modifiers + * are compared (see {@link ModuleDescriptor#compareTo + * ModuleDescriptor.compareTo}). Where the package names are equal and + * the set of modifiers are equal then the set of target modules are + * compared. This is done by sorting the names of the target modules + * in ascending order, and according to their natural ordering, and then + * comparing the corresponding elements lexicographically. Where the + * sets differ in size, and the larger set contains all elements of the + * smaller set, then the larger set is considered to succeed the smaller + * set.

        + * + * @param that + * The module export to compare + * + * @return A negative integer, zero, or a positive integer if this module + * export is less than, equal to, or greater than the given + * export dependence + */ + @Override + public int compareTo(Exports that) { + if (this == that) return 0; + + int c = source.compareTo(that.source); + if (c != 0) + return c; + + // modifiers + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) + return c; + + // targets + c = compare(targets, that.targets); + if (c != 0) + return c; + + return 0; + } + /** * Computes a hash code for this module export. * @@ -425,9 +520,9 @@ public class ModuleDescriptor } /** - * Returns a string describing module export. + * Returns a string describing the exported package. * - * @return A string describing module export + * @return A string describing the exported package */ @Override public String toString() { @@ -441,8 +536,7 @@ public class ModuleDescriptor /** - *

        Represents a module opens directive, may be qualified or - * unqualified.

        + *

        A package opened by a module, may be qualified or unqualified.

        * *

        The opens directive in a module declaration declares a * package to be open to allow all types in the package, and all their @@ -452,26 +546,30 @@ public class ModuleDescriptor * * @see ModuleDescriptor#opens() * @since 9 + * @spec JPMS */ - public final static class Opens { - + public final static class Opens + implements Comparable + { /** - * A modifier on a module opens directive. + * A modifier on an open package. * + * @see Opens#modifiers() * @since 9 + * @spec JPMS */ public static enum Modifier { /** - * The opens was not explicitly or implicitly declared in the - * source of the module declaration. + * The open package was not explicitly or implicitly declared in + * the source of the module declaration. */ SYNTHETIC, /** - * The opens was implicitly declared in the source of the module - * declaration. + * The open package was implicitly declared in the source of the + * module declaration. */ MANDATED; @@ -543,6 +641,52 @@ public class ModuleDescriptor return targets; } + /** + * Compares this module opens to another. + * + *

        Two {@code Opens} objects are compared by comparing the package + * names lexicographically. Where the packages names are equal then the + * sets of modifiers are compared in the same way that module modifiers + * are compared (see {@link ModuleDescriptor#compareTo + * ModuleDescriptor.compareTo}). Where the package names are equal and + * the set of modifiers are equal then the set of target modules are + * compared. This is done by sorting the names of the target modules + * in ascending order, and according to their natural ordering, and then + * comparing the corresponding elements lexicographically. Where the + * sets differ in size, and the larger set contains all elements of the + * smaller set, then the larger set is considered to succeed the smaller + * set.

        + * + * @param that + * The module opens to compare + * + * @return A negative integer, zero, or a positive integer if this module + * opens is less than, equal to, or greater than the given + * module opens + */ + @Override + public int compareTo(Opens that) { + if (this == that) return 0; + + int c = source.compareTo(that.source); + if (c != 0) + return c; + + // modifiers + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) + return c; + + // targets + c = compare(targets, that.targets); + if (c != 0) + return c; + + return 0; + } + /** * Computes a hash code for this module opens. * @@ -588,9 +732,9 @@ public class ModuleDescriptor } /** - * Returns a string describing module opens. + * Returns a string describing the open package. * - * @return A string describing module opens + * @return A string describing the open package */ @Override public String toString() { @@ -608,10 +752,12 @@ public class ModuleDescriptor * * @see ModuleDescriptor#provides() * @since 9 + * @spec JPMS */ - public final static class Provides { - + public final static class Provides + implements Comparable + { private final String service; private final List providers; @@ -641,6 +787,46 @@ public class ModuleDescriptor */ public List providers() { return providers; } + /** + * Compares this provides to another. + * + *

        Two {@code Provides} objects are compared by comparing the fully + * qualified class name of the service type lexicographically. Where the + * class names are equal then the list of the provider class names are + * compared by comparing the corresponding elements of both lists + * lexicographically and in sequence. Where the lists differ in size, + * {@code N} is the size of the shorter list, and the first {@code N} + * corresponding elements are equal, then the longer list is considered + * to succeed the shorter list.

        + * + * @param that + * The {@code Provides} to compare + * + * @return A negative integer, zero, or a positive integer if this provides + * is less than, equal to, or greater than the given provides + */ + public int compareTo(Provides that) { + if (this == that) return 0; + + int c = service.compareTo(that.service); + if (c != 0) return c; + + // compare provider class names in sequence + int size1 = this.providers.size(); + int size2 = that.providers.size(); + for (int index=0; index size2) ? 1 : -1; + } + } + /** * Computes a hash code for this provides. * @@ -699,7 +885,7 @@ public class ModuleDescriptor * *

        A version string has three components: The version number itself, an * optional pre-release version, and an optional build version. Each - * component is sequence of tokens; each token is either a non-negative + * component is a sequence of tokens; each token is either a non-negative * integer or a string. Tokens are separated by the punctuation characters * {@code '.'}, {@code '-'}, or {@code '+'}, or by transitions from a * sequence of digits to a sequence of characters that are neither digits @@ -740,6 +926,7 @@ public class ModuleDescriptor * * @see ModuleDescriptor#version() * @since 9 + * @spec JPMS */ public final static class Version @@ -1009,36 +1196,26 @@ public class ModuleDescriptor } - + private final String name; private final Version version; - private final boolean open; - - // Indicates if synthesised for a JAR file found on the module path - private final boolean automatic; - - // Not generated from a module-info.java - private final boolean synthetic; - + private final Set modifiers; + private final boolean open; // true if modifiers contains OPEN + private final boolean automatic; // true if modifiers contains AUTOMATIC private final Set requires; private final Set exports; private final Set opens; private final Set uses; private final Set provides; - - // Added post-compilation by tools private final Set packages; private final String mainClass; private final String osName; private final String osArch; private final String osVersion; - private ModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set modifiers, Set requires, Set exports, Set opens, @@ -1052,10 +1229,9 @@ public class ModuleDescriptor { this.name = name; this.version = version; - this.open = open; - this.automatic = automatic; - this.synthetic = synthetic; - + this.modifiers = emptyOrUnmodifiableSet(modifiers); + this.open = modifiers.contains(Modifier.OPEN); + this.automatic = modifiers.contains(Modifier.AUTOMATIC); assert (requires.stream().map(Requires::name).distinct().count() == requires.size()); this.requires = emptyOrUnmodifiableSet(requires); @@ -1071,41 +1247,13 @@ public class ModuleDescriptor this.osVersion = osVersion; } - /** - * Clones the given module descriptor with an augmented set of packages - */ - ModuleDescriptor(ModuleDescriptor md, Set pkgs) { - this.name = md.name; - this.version = md.version; - this.open = md.open; - this.automatic = md.automatic; - this.synthetic = md.synthetic; - - this.requires = md.requires; - this.exports = md.exports; - this.opens = md.opens; - this.uses = md.uses; - this.provides = md.provides; - - Set packages = new HashSet<>(md.packages); - packages.addAll(pkgs); - this.packages = emptyOrUnmodifiableSet(packages); - - this.mainClass = md.mainClass; - this.osName = md.osName; - this.osArch = md.osArch; - this.osVersion = md.osVersion; - } - /** * Creates a module descriptor from its components. * The arguments are pre-validated and sets are unmodifiable sets. */ ModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set modifiers, Set requires, Set exports, Set opens, @@ -1120,9 +1268,9 @@ public class ModuleDescriptor boolean unused) { this.name = name; this.version = version; - this.open = open; - this.automatic = automatic; - this.synthetic = synthetic; + this.modifiers = modifiers; + this.open = modifiers.contains(Modifier.OPEN); + this.automatic = modifiers.contains(Modifier.AUTOMATIC); this.requires = requires; this.exports = exports; this.opens = opens; @@ -1137,7 +1285,7 @@ public class ModuleDescriptor } /** - *

        The module name.

        + *

        Returns the module name.

        * * @return The module name */ @@ -1145,12 +1293,20 @@ public class ModuleDescriptor return name; } + /** + *

        Returns the set of module modifiers.

        + * + * @return A possibly-empty unmodifiable set of modifiers + */ + public Set modifiers() { + return modifiers; + } + /** *

        Returns {@code true} if this is an open module.

        * - *

        An open module does not declare any open packages (the {@link #opens() - * opens} method returns an empty set) but the resulting module is treated - * as if all packages are open.

        + *

        This method is equivalent to testing if the set of {@link #modifiers + * modifiers} contains the {@link Modifier#OPEN OPEN} modifier.

        * * @return {@code true} if this is an open module */ @@ -1161,12 +1317,8 @@ public class ModuleDescriptor /** *

        Returns {@code true} if this is an automatic module.

        * - *

        An automatic module is defined implicitly rather than explicitly - * and therefore does not have a module declaration. JAR files located on - * the application module path, or by the {@link ModuleFinder} returned by - * {@link ModuleFinder#of(java.nio.file.Path[]) ModuleFinder.of}, are - * treated as automatic modules if they do have not have a module - * declaration.

        + *

        This method is equivalent to testing if the set of {@link #modifiers + * modifiers} contains the {@link Modifier#OPEN AUTOMATIC} modifier.

        * * @return {@code true} if this is an automatic module */ @@ -1175,20 +1327,13 @@ public class ModuleDescriptor } /** - *

        Returns {@code true} if this module descriptor was not generated - * from an explicit module declaration ({@code module-info.java}) - * or an implicit module declaration (an {@link #isAutomatic() automatic} - * module).

        + *

        Returns the set of {@code Requires} objects representing the module + * dependences.

        * - * @return {@code true} if this module descriptor was not generated by - * an explicit or implicit module declaration - */ - public boolean isSynthetic() { - return synthetic; - } - - /** - *

        The dependences of this module.

        + *

        The set includes a dependency on "{@code java.base}" when this + * module is not named "{@code java.base}". If this module is an automatic + * module then it does not have a dependency on any module other than + * "{@code java.base}".

        * * @return A possibly-empty unmodifiable set of {@link Requires} objects */ @@ -1197,7 +1342,11 @@ public class ModuleDescriptor } /** - *

        The module exports.

        + *

        Returns the set of {@code Exports} objects representing the exported + * packages.

        + * + *

        If this module is an automatic module then the set of exports + * is empty.

        * * @return A possibly-empty unmodifiable set of exported packages */ @@ -1206,16 +1355,11 @@ public class ModuleDescriptor } /** - *

        The module opens directives.

        + *

        Returns the set of {@code Opens} objects representing the open + * packages.

        * - *

        Each {@code Opens} object in the set represents a package (and - * the set of target module names when qualified) where all types in the - * package, and all their members, not just public types and their public - * members, can be reflected on when using APIs that bypass or suppress - * default Java language access control checks.

        - * - *

        This method returns an empty set when invoked on {@link #isOpen() - * open} module.

        + *

        If this module is an open module or an automatic module then the + * set of open packages is empty.

        * * @return A possibly-empty unmodifiable set of open packages */ @@ -1224,7 +1368,10 @@ public class ModuleDescriptor } /** - *

        The service dependences of this module.

        + *

        Returns the set of service dependences.

        + * + *

        If this module is an automatic module then the set of service + * dependences is empty.

        * * @return A possibly-empty unmodifiable set of the fully qualified class * names of the service types used @@ -1234,7 +1381,8 @@ public class ModuleDescriptor } /** - *

        The services that this module provides.

        + *

        Returns the set of {@code Provides} objects representing the + * services that the module provides.

        * * @return The possibly-empty unmodifiable set of the services that this * module provides @@ -1244,7 +1392,7 @@ public class ModuleDescriptor } /** - * Returns this module's version. + *

        Returns the module version.

        * * @return This module's version */ @@ -1253,10 +1401,10 @@ public class ModuleDescriptor } /** - * Returns a string containing this module's name and, if present, its - * version. + *

        Returns a string containing the module name and, if present, its + * version.

        * - * @return A string containing this module's name and, if present, its + * @return A string containing the module name and, if present, its * version. */ public String toNameAndVersion() { @@ -1268,51 +1416,51 @@ public class ModuleDescriptor } /** - * Returns the module's main class. + *

        Returns the module main class.

        * - * @return The fully qualified class name of this module's main class + * @return The fully qualified class name of the module's main class */ public Optional mainClass() { return Optional.ofNullable(mainClass); } /** - * Returns the operating system name if this module is operating system + * Returns the operating system name if the module is operating system * specific. * * @return The operating system name or an empty {@code Optional} - * if this module is not operating system specific + * if the module is not operating system specific */ public Optional osName() { return Optional.ofNullable(osName); } /** - * Returns the operating system architecture if this module is operating + * Returns the operating system architecture if the module is operating * system architecture specific. * * @return The operating system architecture or an empty {@code Optional} - * if this module is not operating system architecture specific + * if the module is not operating system architecture specific */ public Optional osArch() { return Optional.ofNullable(osArch); } /** - * Returns the operating system version if this module is operating + * Returns the operating system version if the module is operating * system version specific. * * @return The operating system version or an empty {@code Optional} - * if this module is not operating system version specific + * if the module is not operating system version specific */ public Optional osVersion() { return Optional.ofNullable(osVersion); } /** - * Returns the names of all packages in this module. + * Returns the set of packages in the module. * - * @return A possibly-empty unmodifiable set of all packages in the module + * @return A possibly-empty unmodifiable set of the packages in the module */ public Set packages() { return packages; @@ -1320,37 +1468,53 @@ public class ModuleDescriptor /** - * A builder used for building {@link ModuleDescriptor} objects. + * A builder for building {@link ModuleDescriptor} objects. * - *

        {@code ModuleDescriptor} defines the {@link #module module}, {@link - * #openModule openModule}, and {@link #automaticModule automaticModule} - * methods to create builders for building different kinds of modules.

        + *

        {@code ModuleDescriptor} defines the {@link #newModule newModule}, + * {@link #newOpenModule newOpenModule}, and {@link #newAutomaticModule + * newAutomaticModule} methods to create builders for building + * normal, open, and automatic modules.

        + * + *

        The set of packages in the module are accumulated by the {@code + * Builder} as the {@link ModuleDescriptor.Builder#exports(String) exports}, + * {@link ModuleDescriptor.Builder#opens(String) opens}, + * {@link ModuleDescriptor.Builder#packages(Set) packages}, + * {@link ModuleDescriptor.Builder#provides(String,List) provides}, and + * {@link ModuleDescriptor.Builder#mainClass(String) mainClass} methods are + * invoked.

        + * + *

        The module names, package names, and class names that are parameters + * specified to the builder methods are the module names, package names, + * and qualified names of classes (in named packages) as defined in the + * The Java™ Language Specification.

        * *

        Example usage:

        - *
        {@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
        -     *         .exports("p")
        -     *         .requires("m2")
        +     * 
        {@code    ModuleDescriptor descriptor = ModuleDescriptor.newModule("stats.core")
        +     *         .requires("java.base")
        +     *         .exports("org.acme.stats.core.clustering")
        +     *         .exports("org.acme.stats.core.regression")
        +     *         .packages(Set.of("org.acme.stats.core.internal"))
              *         .build();
              * }
        * * @apiNote A {@code Builder} checks the components and invariants as - * components are added to the builder. The rational for this is to detect + * components are added to the builder. The rationale for this is to detect * errors as early as possible and not defer all validation to the - * {@link #build build} method. A {@code Builder} cannot be used to create - * a {@link ModuleDescriptor#isSynthetic() synthetic} module. + * {@link #build build} method. * * @since 9 + * @spec JPMS */ public static final class Builder { final String name; - final boolean strict; // true if module names are checked + final boolean strict; + final Set modifiers; final boolean open; - final boolean synthetic; - boolean automatic; + final boolean automatic; + final Set packages = new HashSet<>(); final Map requires = new HashMap<>(); final Map exports = new HashMap<>(); final Map opens = new HashMap<>(); - final Set concealedPackages = new HashSet<>(); final Set uses = new HashSet<>(); final Map provides = new HashMap<>(); Version version; @@ -1362,35 +1526,25 @@ public class ModuleDescriptor /** * Initializes a new builder with the given module name. * - * @param strict - * Indicates whether module names are checked or not + * If {@code strict} is {@code true} then module, package, and class + * names are checked to ensure they are legal names. In addition, the + * {@link #build buid} method will add "{@code requires java.base}" if + * the dependency is not declared. */ - Builder(String name, boolean strict, boolean open, boolean synthetic) { + Builder(String name, boolean strict, Set modifiers) { this.name = (strict) ? requireModuleName(name) : name; this.strict = strict; - this.open = open; - this.synthetic = synthetic; - } - - /* package */ Builder automatic(boolean automatic) { - this.automatic = automatic; - return this; + this.modifiers = modifiers; + this.open = modifiers.contains(Modifier.OPEN); + this.automatic = modifiers.contains(Modifier.AUTOMATIC); + assert !open || !automatic; } /** - * Returns the set of packages that are exported (unconditionally or - * unconditionally). + * Returns a snapshot of the packages in the module. */ - /* package */ Set exportedPackages() { - return exports.keySet(); - } - - /** - * Returns the set of packages that are opened (unconditionally or - * unconditionally). - */ - /* package */Set openPackages() { - return opens.keySet(); + /* package */ Set packages() { + return Collections.unmodifiableSet(packages); } /** @@ -1406,8 +1560,12 @@ public class ModuleDescriptor * initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(Requires req) { + if (automatic) + throw new IllegalStateException("Automatic modules cannot declare" + + " dependences"); String mn = req.name(); if (name.equals(mn)) throw new IllegalArgumentException("Dependence on self"); @@ -1433,11 +1591,12 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the module name is {@code null}, is not a legal Java - * identifier, or is equal to the module name that this builder + * If the module name is {@code null}, is not a legal module + * name, or is equal to the module name that this builder * was initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(Set ms, String mn, @@ -1448,6 +1607,23 @@ public class ModuleDescriptor return requires(new Requires(ms, mn, compiledVersion)); } + /* package */Builder requires(Set ms, + String mn, + String compiledVersion) { + Version v = null; + try { + v = Version.parse(compiledVersion); + } catch (IllegalArgumentException e) { + // for now, drop un-parsable version when non-strict + if (strict) throw e; + } + if (v == null) { + return requires(ms, mn); + } else { + return requires(ms, mn, v); + } + } + /** * Adds a dependence on a module with the given (and possibly empty) * set of modifiers. @@ -1460,11 +1636,12 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the module name is {@code null}, is not a legal Java - * identifier, or is equal to the module name that this builder + * If the module name is {@code null}, is not a legal module + * name, or is equal to the module name that this builder * was initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(Set ms, String mn) { if (strict) @@ -1481,18 +1658,19 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the module name is {@code null}, is not a legal Java - * identifier, or is equal to the module name that this builder + * If the module name is {@code null}, is not a legal module + * name, or is equal to the module name that this builder * was initialized to build * @throws IllegalStateException * If the dependence on the module has already been declared + * or this builder is for an automatic module */ public Builder requires(String mn) { return requires(EnumSet.noneOf(Requires.Modifier.class), mn); } /** - * Adds an export. + * Adds an exported package. * * @param e * The export @@ -1500,29 +1678,27 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported + * If the {@link Exports#source package} is already declared as + * exported or this builder is for an automatic module */ public Builder exports(Exports e) { - // can't be exported and concealed - String source = e.source(); - if (concealedPackages.contains(source)) { - throw new IllegalStateException("Package " + source - + " already declared"); + if (automatic) { + throw new IllegalStateException("Automatic modules cannot declare" + + " exported packages"); } + String source = e.source(); if (exports.containsKey(source)) { throw new IllegalStateException("Exported package " + source + " already declared"); } - exports.put(source, e); + packages.add(source); return this; } /** - * Adds an export, with the given (and possibly empty) set of modifiers, - * to export a package to a set of target modules. + * Adds an exported package with the given (and possibly empty) set of + * modifiers. The package is exported to a set of target modules. * * @param ms * The set of modifiers @@ -1534,33 +1710,34 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported + * If the package is already declared as exported + * or this builder is for an automatic module */ public Builder exports(Set ms, String pn, Set targets) { - Exports e = new Exports(ms, requirePackageName(pn), targets); + Exports e = new Exports(ms, pn, targets); // check targets targets = e.targets(); if (targets.isEmpty()) throw new IllegalArgumentException("Empty target set"); - if (strict) + if (strict) { + requirePackageName(e.source()); targets.stream().forEach(Checks::requireModuleName); - + } return exports(e); } /** - * Adds an unqualified export with the given (and possibly empty) set - * of modifiers. + * Adds an exported package with the given (and possibly empty) set of + * modifiers. The package is exported to all modules. * * @param ms * The set of modifiers @@ -1570,160 +1747,22 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier + * If the package name is {@code null} or is not a legal + * package name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported + * If the package is already declared as exported + * or this builder is for an automatic module */ public Builder exports(Set ms, String pn) { - Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet()); + if (strict) { + requirePackageName(pn); + } + Exports e = new Exports(ms, pn, Collections.emptySet()); return exports(e); } /** - * Adds an export to export a package to a set of target modules. - * - * @param pn - * The package name - * @param targets - * The set of target modules names - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported - */ - public Builder exports(String pn, Set targets) { - return exports(Collections.emptySet(), pn, targets); - } - - /** - * Adds an unqualified export. - * - * @param pn - * The package name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method or the package is already - * declared as exported - */ - public Builder exports(String pn) { - return exports(Collections.emptySet(), pn); - } - - /** - * Adds an opens directive. - * - * @param obj - * The {@code Opens} object - * - * @return This builder - * - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module - */ - public Builder opens(Opens obj) { - if (open) { - throw new IllegalStateException("open modules cannot declare" - + " open packages"); - } - - // can't be open and concealed - String source = obj.source(); - if (concealedPackages.contains(source)) { - throw new IllegalStateException("Package " + source - + " already declared"); - } - if (opens.containsKey(source)) { - throw new IllegalStateException("Open package " + source - + " already declared"); - } - - opens.put(source, obj); - return this; - } - - - /** - * Adds an opens directive, with the given (and possibly empty) - * set of modifiers, to open a package to a set of target modules. - * - * @param ms - * The set of modifiers - * @param pn - * The package name - * @param targets - * The set of target modules names - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module - */ - public Builder opens(Set ms, - String pn, - Set targets) - { - Opens e = new Opens(ms, requirePackageName(pn), targets); - - // check targets - targets = e.targets(); - if (targets.isEmpty()) - throw new IllegalArgumentException("Empty target set"); - if (strict) - targets.stream().forEach(Checks::requireModuleName); - - return opens(e); - } - - /** - * Adds an opens directive to open a package with the given (and - * possibly empty) set of modifiers. - * - * @param ms - * The set of modifiers - * @param pn - * The package name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier - * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module - */ - public Builder opens(Set ms, String pn) { - Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet()); - return opens(e); - } - - /** - * Adds an opens directive to open a package to a set of target + * Adds an exported package. The package is exported to a set of target * modules. * * @param pn @@ -1734,20 +1773,20 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name or any of the target modules is {@code - * null} or is not a legal Java identifier, or the set of - * targets is empty + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module + * If the package is already declared as exported + * or this builder is for an automatic module */ - public Builder opens(String pn, Set targets) { - return opens(Collections.emptySet(), pn, targets); + public Builder exports(String pn, Set targets) { + return exports(Collections.emptySet(), pn, targets); } /** - * Adds an opens directive to open a package. + * Adds an exported package. The package is exported to all modules. * * @param pn * The package name @@ -1755,12 +1794,146 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the package name is {@code null} or is not a legal Java - * identifier + * If the package name is {@code null} or is not a legal + * package name * @throws IllegalStateException - * If the package is already declared as a package with the - * {@link #contains contains} method, the package is already - * declared as open, or this is a builder for an open module + * If the package is already declared as exported + * or this builder is for an automatic module + */ + public Builder exports(String pn) { + return exports(Collections.emptySet(), pn); + } + + /** + * Adds an open package. + * + * @param obj + * The {@code Opens} object + * + * @return This builder + * + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(Opens obj) { + if (open || automatic) { + throw new IllegalStateException("Open or automatic modules cannot" + + " declare open packages"); + } + String source = obj.source(); + if (opens.containsKey(source)) { + throw new IllegalStateException("Open package " + source + + " already declared"); + } + opens.put(source, obj); + packages.add(source); + return this; + } + + + /** + * Adds an open package with the given (and possibly empty) set of + * modifiers. The package is open to a set of target modules. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * @param targets + * The set of target modules names + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(Set ms, + String pn, + Set targets) + { + Opens opens = new Opens(ms, pn, targets); + + // check targets + targets = opens.targets(); + if (targets.isEmpty()) + throw new IllegalArgumentException("Empty target set"); + if (strict) { + requirePackageName(opens.source()); + targets.stream().forEach(Checks::requireModuleName); + } + return opens(opens); + } + + /** + * Adds an open package with the given (and possibly empty) set of + * modifiers. The package is open to all modules. + * + * @param ms + * The set of modifiers + * @param pn + * The package name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(Set ms, String pn) { + if (strict) { + requirePackageName(pn); + } + Opens e = new Opens(ms, pn, Collections.emptySet()); + return opens(e); + } + + /** + * Adds an open package. The package is open to a set of target modules. + * + * @param pn + * The package name + * @param targets + * The set of target modules names + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name, the set of target modules is empty, or the set + * of target modules contains a name that is not a legal module + * name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module + */ + public Builder opens(String pn, Set targets) { + return opens(Collections.emptySet(), pn, targets); + } + + /** + * Adds an open package. The package is open to all modules. + * + * @param pn + * The package name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name is {@code null} or is not a legal + * package name + * @throws IllegalStateException + * If the package is already declared as open, or this is a + * builder for an open module or automatic module */ public Builder opens(String pn) { return opens(Collections.emptySet(), pn); @@ -1775,12 +1948,16 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If the service type is {@code null} or is not a legal Java - * identifier + * If the service type is {@code null} or not a qualified name of + * a class in a named package * @throws IllegalStateException * If a dependency on the service type has already been declared + * or this is a builder for an an automatic module */ public Builder uses(String service) { + if (automatic) + throw new IllegalStateException("Automatic modules can not declare" + + " service dependences"); if (uses.contains(requireServiceTypeName(service))) throw new IllegalStateException("Dependence upon service " + service + " already declared"); @@ -1789,7 +1966,9 @@ public class ModuleDescriptor } /** - * Provides a service with one or more implementations. + * Provides a service with one or more implementations. The package for + * each {@link Provides#providers provider} (or provider factory) is + * added to the module if not already added. * * @param p * The provides @@ -1801,16 +1980,18 @@ public class ModuleDescriptor * declared */ public Builder provides(Provides p) { - String st = p.service(); - if (provides.containsKey(st)) + String service = p.service(); + if (provides.containsKey(service)) throw new IllegalStateException("Providers of service " - + st + " already declared"); - provides.put(st, p); + + service + " already declared"); + provides.put(service, p); + p.providers().forEach(name -> packages.add(packageName(name))); return this; } /** - * Provides implementations of a service. + * Provides implementations of a service. The package for each provider + * (or provider factory) is added to the module if not already added. * * @param service * The service type @@ -1821,103 +2002,59 @@ public class ModuleDescriptor * * @throws IllegalArgumentException * If the service type or any of the provider class names is - * {@code null} or is not a legal Java identifier, or the list - * of provider class names is empty + * {@code null} or not a qualified name of a class in a named + * package, or the list of provider class names is empty * @throws IllegalStateException * If the providers for the service type have already been * declared */ public Builder provides(String service, List providers) { - if (provides.containsKey(service)) - throw new IllegalStateException("Providers of service " - + service + " already declared by " + name); - - Provides p = new Provides(requireServiceTypeName(service), providers); + Provides p = new Provides(service, providers); // check providers after the set has been copied. List providerNames = p.providers(); if (providerNames.isEmpty()) throw new IllegalArgumentException("Empty providers set"); - providerNames.forEach(Checks::requireServiceProviderName); - provides.put(service, p); - return this; + if (strict) { + requireServiceTypeName(p.service()); + providerNames.forEach(Checks::requireServiceProviderName); + } else { + // Disallow service/providers in unnamed package + String pn = packageName(service); + if (pn.isEmpty()) { + throw new IllegalArgumentException(service + + ": unnamed package"); + } + for (String name : providerNames) { + pn = packageName(name); + if (pn.isEmpty()) { + throw new IllegalArgumentException(name + + ": unnamed package"); + } + } + } + return provides(p); } /** - * Provides an implementation of a service. - * - * @param service - * The service type - * @param provider - * The provider or provider factory class name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the service type or the provider class name is {@code - * null} or is not a legal Java identifier - * @throws IllegalStateException - * If the providers for the service type have already been - * declared - */ - public Builder provides(String service, String provider) { - if (provider == null) - throw new IllegalArgumentException("'provider' is null"); - return provides(service, List.of(provider)); - } - - /** - * Adds a (possible empty) set of packages to the module + * Adds packages to the module. All packages in the set of package names + * that are not in the module are added to module. * * @param pns - * The set of package names + * The (possibly empty) set of package names * * @return This builder * * @throws IllegalArgumentException * If any of the package names is {@code null} or is not a - * legal Java identifier - * @throws IllegalStateException - * If any of packages are already declared as packages in - * the module. This includes packages that are already - * declared as exported or open packages. + * legal package name */ - public Builder contains(Set pns) { - pns.forEach(this::contains); - return this; - } - - /** - * Adds a package to the module. - * - * @param pn - * The package name - * - * @return This builder - * - * @throws IllegalArgumentException - * If the package name is {@code null}, or is not a legal Java - * identifier - * @throws IllegalStateException - * If the package is already declared as a package in the - * module. This includes the package already declared as an - * exported or open package. - */ - public Builder contains(String pn) { - Checks.requirePackageName(pn); - if (concealedPackages.contains(pn)) { - throw new IllegalStateException("Package " + pn - + " already declared"); + public Builder packages(Set pns) { + if (strict) { + pns = new HashSet<>(pns); + pns.forEach(Checks::requirePackageName); } - if (exports.containsKey(pn)) { - throw new IllegalStateException("Exported package " - + pn + " already declared"); - } - if (opens.containsKey(pn)) { - throw new IllegalStateException("Open package " - + pn + " already declared"); - } - concealedPackages.add(pn); + this.packages.addAll(pns); return this; } @@ -1937,22 +2074,35 @@ public class ModuleDescriptor /** * Sets the module version. * - * @param v + * @param vs * The version string to parse * * @return This builder * * @throws IllegalArgumentException - * If {@code v} is null or cannot be parsed as a version string + * If {@code vs} is {@code null} or cannot be parsed as a + * version string * * @see Version#parse(String) */ - public Builder version(String v) { - return version(Version.parse(v)); + public Builder version(String vs) { + Version v; + if (strict) { + v = Version.parse(vs); + } else { + try { + v = Version.parse(vs); + } catch (IllegalArgumentException ignore) { + // for now, ignore when non-strict + return this; + } + } + return version(v); } /** - * Sets the module main class. + * Sets the module main class. The package for the main class is added + * to the module if not already added. * * @param mc * The module main class @@ -1960,10 +2110,24 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code mainClass} is null or is not a legal Java identifier + * If {@code mainClass} is {@code null} or not a qualified + * name of a class in a named package */ public Builder mainClass(String mc) { - mainClass = requireBinaryName("main class name", mc); + String pn; + if (strict) { + mc = requireQualifiedClassName("main class name", mc); + pn = packageName(mc); + assert !pn.isEmpty(); + } else { + // Disallow main class in unnamed package + pn = packageName(mc); + if (pn.isEmpty()) { + throw new IllegalArgumentException(mc + ": unnamed package"); + } + } + mainClass = mc; + packages.add(pn); return this; } @@ -1976,7 +2140,7 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code name} is null or the empty String + * If {@code name} is {@code null} or the empty String */ public Builder osName(String name) { if (name == null || name.isEmpty()) @@ -1994,7 +2158,7 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code name} is null or the empty String + * If {@code name} is {@code null} or the empty String */ public Builder osArch(String arch) { if (arch == null || arch.isEmpty()) @@ -2012,7 +2176,7 @@ public class ModuleDescriptor * @return This builder * * @throws IllegalArgumentException - * If {@code name} is null or the empty String + * If {@code name} is {@code null} or the empty String */ public Builder osVersion(String version) { if (version == null || version.isEmpty()) @@ -2024,26 +2188,34 @@ public class ModuleDescriptor /** * Builds and returns a {@code ModuleDescriptor} from its components. * + *

        The module will require "{@code java.base}" even if the dependence + * has not been declared (the exception is when building a module named + * "{@code java.base}" as it cannot require itself). The dependence on + * "{@code java.base}" will have the {@link + * java.lang.module.ModuleDescriptor.Requires.Modifier#MANDATED MANDATED} + * modifier if the dependence was not declared.

        + * * @return The module descriptor */ public ModuleDescriptor build() { Set requires = new HashSet<>(this.requires.values()); - - Set packages = new HashSet<>(); - packages.addAll(exports.keySet()); - packages.addAll(opens.keySet()); - packages.addAll(concealedPackages); - Set exports = new HashSet<>(this.exports.values()); Set opens = new HashSet<>(this.opens.values()); + // add dependency on java.base + if (strict + && !name.equals("java.base") + && !this.requires.containsKey("java.base")) { + requires.add(new Requires(Set.of(Requires.Modifier.MANDATED), + "java.base", + null)); + } + Set provides = new HashSet<>(this.provides.values()); return new ModuleDescriptor(name, version, - open, - automatic, - synthetic, + modifiers, requires, exports, opens, @@ -2062,16 +2234,20 @@ public class ModuleDescriptor * Compares this module descriptor to another. * *

        Two {@code ModuleDescriptor} objects are compared by comparing their - * module name lexicographically. Where the module names are equal then - * the versions, if present, are compared.

        - * - * @apiNote For now, the natural ordering is not consistent with equals. - * If two module descriptors have equal module names, equal versions if - * present, but their corresponding components are not equal, then they - * will be considered equal by this method. + * module names lexicographically. Where the module names are equal then the + * module versions are compared. When comparing the module versions then a + * module descriptor with a version is considered to succeed a module + * descriptor that does not have a version. Where the module names are equal + * and the versions are equal (or not present in both), then the set of + * modifiers are compared. Sets of modifiers are compared by comparing + * a binary value computed for each set. If a modifier is present + * in the set then the bit at the position of its ordinal is {@code 1} + * in the binary value, otherwise {@code 0}. If the two set of modifiers + * are also equal then the other components of the module descriptors are + * compared in a manner that is consistent with {@code equals}.

        * * @param that - * The object to which this module descriptor is to be compared + * The module descriptor to compare * * @return A negative integer, zero, or a positive integer if this module * descriptor is less than, equal to, or greater than the given @@ -2079,16 +2255,50 @@ public class ModuleDescriptor */ @Override public int compareTo(ModuleDescriptor that) { + if (this == that) return 0; + int c = this.name().compareTo(that.name()); if (c != 0) return c; - if (version == null) { - if (that.version == null) - return 0; - return -1; - } - if (that.version == null) - return +1; - return version.compareTo(that.version); + + c = compare(this.version, that.version); + if (c != 0) return c; + + long v1 = modsValue(this.modifiers()); + long v2 = modsValue(that.modifiers()); + c = Long.compare(v1, v2); + if (c != 0) return c; + + c = compare(this.requires, that.requires); + if (c != 0) return c; + + c = compare(this.packages, that.packages); + if (c != 0) return c; + + c = compare(this.exports, that.exports); + if (c != 0) return c; + + c = compare(this.opens, that.opens); + if (c != 0) return c; + + c = compare(this.uses, that.uses); + if (c != 0) return c; + + c = compare(this.provides, that.provides); + if (c != 0) return c; + + c = compare(this.mainClass, that.mainClass); + if (c != 0) return c; + + c = compare(this.osName, that.osName); + if (c != 0) return c; + + c = compare(this.osArch, that.osArch); + if (c != 0) return c; + + c = compare(this.osVersion, that.osVersion); + if (c != 0) return c; + + return 0; } /** @@ -2115,10 +2325,9 @@ public class ModuleDescriptor return false; ModuleDescriptor that = (ModuleDescriptor)ob; return (name.equals(that.name) - && open == that.open - && automatic == that.automatic - && synthetic == that.synthetic + && modifiers.equals(that.modifiers) && requires.equals(that.requires) + && Objects.equals(packages, that.packages) && exports.equals(that.exports) && opens.equals(that.opens) && uses.equals(that.uses) @@ -2127,12 +2336,9 @@ public class ModuleDescriptor && Objects.equals(mainClass, that.mainClass) && Objects.equals(osName, that.osName) && Objects.equals(osArch, that.osArch) - && Objects.equals(osVersion, that.osVersion) - && Objects.equals(packages, that.packages)); + && Objects.equals(osVersion, that.osVersion)); } - private transient int hash; // cached hash code - /** * Computes a hash code for this module descriptor. * @@ -2147,10 +2353,9 @@ public class ModuleDescriptor int hc = hash; if (hc == 0) { hc = name.hashCode(); - hc = hc * 43 + Boolean.hashCode(open); - hc = hc * 43 + Boolean.hashCode(automatic); - hc = hc * 43 + Boolean.hashCode(synthetic); + hc = hc * 43 + Objects.hashCode(modifiers); hc = hc * 43 + requires.hashCode(); + hc = hc * 43 + Objects.hashCode(packages); hc = hc * 43 + exports.hashCode(); hc = hc * 43 + opens.hashCode(); hc = hc * 43 + uses.hashCode(); @@ -2160,18 +2365,18 @@ public class ModuleDescriptor hc = hc * 43 + Objects.hashCode(osName); hc = hc * 43 + Objects.hashCode(osArch); hc = hc * 43 + Objects.hashCode(osVersion); - hc = hc * 43 + Objects.hashCode(packages); if (hc == 0) hc = -1; hash = hc; } return hc; } + private transient int hash; // cached hash code /** - * Returns a string describing this descriptor. + *

        Returns a string describing the module.

        * - * @return A string describing this descriptor + * @return A string describing the module */ @Override public String toString() { @@ -2201,31 +2406,50 @@ public class ModuleDescriptor * * @param name * The module name + * @param ms + * The set of module modifiers * * @return A new builder * * @throws IllegalArgumentException - * If the module name is {@code null} or is not a legal Java - * identifier + * If the module name is {@code null} or is not a legal module + * name, or the set of modifiers contains {@link + * Modifier#AUTOMATIC AUTOMATIC} with other modifiers */ - public static Builder module(String name) { - return new Builder(name, true, false, false); + public static Builder newModule(String name, Set ms) { + Set mods = new HashSet<>(ms); + if (mods.contains(Modifier.AUTOMATIC) && mods.size() > 1) + throw new IllegalArgumentException("AUTOMATIC cannot be used with" + + " other modifiers"); + + return new Builder(name, true, mods); + } + + /** + * Instantiates a builder to build a module descriptor for a normal + * module. This method is equivalent to invoking {@link #newModule(String,Set) + * newModule} with an empty set of {@link ModuleDescriptor.Modifier modifiers}. + * + * @param name + * The module name + * + * @return A new builder + * + * @throws IllegalArgumentException + * If the module name is {@code null} or is not a legal module + * name + */ + public static Builder newModule(String name) { + return new Builder(name, true, Set.of()); } /** * Instantiates a builder to build a module descriptor for an open module. - * An open module does not declare any open packages but the resulting - * module is treated as if all packages are open. + * This method is equivalent to invoking {@link #newModule(String,Set) + * newModule} with the {@link ModuleDescriptor.Modifier#OPEN OPEN} modifier. * - *

        As an example, the following creates a module descriptor for an open - * name "{@code m}" containing two packages, one of which is exported.

        - *
        {@code
        -     *     ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
        -     *         .requires("java.base")
        -     *         .exports("p")
        -     *         .contains("q")
        -     *         .build();
        -     * }
        + *

        The builder for an open module cannot be used to declare any open + * packages.

        * * @param name * The module name @@ -2233,19 +2457,22 @@ public class ModuleDescriptor * @return A new builder that builds an open module * * @throws IllegalArgumentException - * If the module name is {@code null} or is not a legal Java - * identifier + * If the module name is {@code null} or is not a legal module + * name */ - public static Builder openModule(String name) { - return new Builder(name, true, true, false); + public static Builder newOpenModule(String name) { + return new Builder(name, true, Set.of(Modifier.OPEN)); } /** * Instantiates a builder to build a module descriptor for an automatic - * module. Automatic modules receive special treatment during resolution - * (see {@link Configuration}) so that they read all other modules. When - * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module} - * then the Module reads every unnamed module in the Java virtual machine. + * module. This method is equivalent to invoking {@link #newModule(String,Set) + * newModule} with the {@link ModuleDescriptor.Modifier#AUTOMATIC AUTOMATIC} + * modifier. + * + *

        The builder for an automatic module cannot be used to declare module + * or service dependences. It also cannot be used to declare any exported + * or open packages.

        * * @param name * The module name @@ -2253,13 +2480,13 @@ public class ModuleDescriptor * @return A new builder that builds an automatic module * * @throws IllegalArgumentException - * If the module name is {@code null} or is not a legal Java - * identifier + * If the module name is {@code null} or is not a legal module + * name * * @see ModuleFinder#of(Path[]) */ - public static Builder automaticModule(String name) { - return new Builder(name, true, false, false).automatic(true); + public static Builder newAutomaticModule(String name) { + return new Builder(name, true, Set.of(Modifier.AUTOMATIC)); } @@ -2269,8 +2496,12 @@ public class ModuleDescriptor * *

        If the descriptor encoded in the input stream does not indicate a * set of packages in the module then the {@code packageFinder} will be - * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException} - * then {@link IOException} cause will be re-thrown.

        + * invoked. The set of packages that the {@code packageFinder} returns + * must include all the packages that the module exports, opens, as well + * as the packages of the service implementations that the module provides, + * and the package of the main class (if the module has a main class). If + * the {@code packageFinder} throws an {@link UncheckedIOException} then + * {@link IOException} cause will be re-thrown.

        * *

        If there are bytes following the module descriptor then it is * implementation specific as to whether those bytes are read, ignored, @@ -2292,7 +2523,9 @@ public class ModuleDescriptor * @return The module descriptor * * @throws InvalidModuleDescriptorException - * If an invalid module descriptor is detected + * If an invalid module descriptor is detected or the set of + * packages returned by the {@code packageFinder} does not include + * all of the packages obtained from the module descriptor * @throws IOException * If an I/O error occurs reading from the input stream or {@code * UncheckedIOException} is thrown by the package finder @@ -2305,8 +2538,12 @@ public class ModuleDescriptor } /** - * Reads the binary form of a module declaration from an input stream - * as a module descriptor. + * Reads the binary form of a module declaration from an input stream as a + * module descriptor. This method works exactly as specified by the 2-arg + * {@link #read(InputStream,Supplier) read} method with the exception that + * a packager finder is not used to find additional packages when the + * module descriptor read from the stream does not indicate the set of + * packages. * * @param in * The input stream @@ -2327,7 +2564,13 @@ public class ModuleDescriptor * as a module descriptor. * *

        If the descriptor encoded in the byte buffer does not indicate a - * set of packages then the {@code packageFinder} will be invoked.

        + * set of packages in the module then the {@code packageFinder} will be + * invoked. The set of packages that the {@code packageFinder} returns + * must include all the packages that the module exports, opens, as well + * as the packages of the service implementations that the module provides, + * and the package of the main class (if the module has a main class). If + * the {@code packageFinder} throws an {@link UncheckedIOException} then + * {@link IOException} cause will be re-thrown.

        * *

        The module descriptor is read from the buffer stating at index * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position() @@ -2353,7 +2596,9 @@ public class ModuleDescriptor * @return The module descriptor * * @throws InvalidModuleDescriptorException - * If an invalid module descriptor is detected + * If an invalid module descriptor is detected or the set of + * packages returned by the {@code packageFinder} does not include + * all of the packages obtained from the module descriptor */ public static ModuleDescriptor read(ByteBuffer bb, Supplier> packageFinder) @@ -2362,8 +2607,11 @@ public class ModuleDescriptor } /** - * Reads the binary form of a module declaration from a byte buffer - * as a module descriptor. + * Reads the binary form of a module declaration from a byte buffer as a + * module descriptor. This method works exactly as specified by the 2-arg + * {@link #read(ByteBuffer,Supplier) read} method with the exception that a + * packager finder is not used to find additional packages when the module + * descriptor encoded in the buffer does not indicate the set of packages. * * @param bb * The byte buffer @@ -2398,6 +2646,11 @@ public class ModuleDescriptor } } + private static String packageName(String cn) { + int index = cn.lastIndexOf('.'); + return (index == -1) ? "" : cn.substring(0, index); + } + /** * Returns a string containing the given set of modifiers and label. */ @@ -2407,6 +2660,36 @@ public class ModuleDescriptor .collect(Collectors.joining(" ")); } + private static > + int compare(T obj1, T obj2) { + if (obj1 != null) { + return (obj2 != null) ? obj1.compareTo(obj2) : 1; + } else { + return (obj2 == null) ? 0 : -1; + } + } + + /** + * Compares two sets of {@code Comparable} objects. + */ + @SuppressWarnings("unchecked") + private static > + int compare(Set s1, Set s2) { + T[] a1 = (T[]) s1.toArray(); + T[] a2 = (T[]) s2.toArray(); + Arrays.sort(a1); + Arrays.sort(a2); + return Arrays.compare(a1, a2); + } + + private static > long modsValue(Set set) { + long value = 0; + for (Enum e : set) { + value += 1 << e.ordinal(); + } + return value; + } + static { /** * Setup the shared secret to allow code in other packages access @@ -2417,19 +2700,21 @@ public class ModuleDescriptor @Override public Builder newModuleBuilder(String mn, boolean strict, - boolean open, - boolean synthetic) { - return new Builder(mn, strict, open, synthetic); + Set modifiers) { + return new Builder(mn, strict, modifiers); } @Override - public Set exportedPackages(ModuleDescriptor.Builder builder) { - return builder.exportedPackages(); + public Set packages(ModuleDescriptor.Builder builder) { + return builder.packages(); } @Override - public Set openPackages(ModuleDescriptor.Builder builder) { - return builder.openPackages(); + public void requires(ModuleDescriptor.Builder builder, + Set ms, + String mn, + String compiledVersion) { + builder.requires(ms, mn, compiledVersion); } @Override @@ -2466,23 +2751,10 @@ public class ModuleDescriptor return new Provides(service, providers, true); } - @Override - public Version newVersion(String v) { - return new Version(v); - } - - @Override - public ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, - Set pkgs) { - return new ModuleDescriptor(md, pkgs); - } - @Override public ModuleDescriptor newModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set modifiers, Set requires, Set exports, Set opens, @@ -2496,9 +2768,7 @@ public class ModuleDescriptor int hashCode) { return new ModuleDescriptor(name, version, - open, - automatic, - synthetic, + modifiers, requires, exports, opens, @@ -2514,12 +2784,12 @@ public class ModuleDescriptor } @Override - public Configuration resolveRequiresAndUses(ModuleFinder finder, - Collection roots, - boolean check, - PrintStream traceOutput) + public Configuration resolveAndBind(ModuleFinder finder, + Collection roots, + boolean check, + PrintStream traceOutput) { - return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput); + return Configuration.resolveAndBind(finder, roots, check, traceOutput); } }); } diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java index 5d01f698806..9fc03dc87b5 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,14 +42,15 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.ModulePath; import jdk.internal.module.SystemModuleFinder; import sun.security.action.GetPropertyAction; /** * A finder of modules. A {@code ModuleFinder} is used to find modules during - * resolution or - * service binding. + * resolution or + * service binding. * *

        A {@code ModuleFinder} can only find one module with a given name. A * {@code ModuleFinder} that finds modules in a sequence of directories, for @@ -85,6 +86,7 @@ import sun.security.action.GetPropertyAction; *

        A {@code ModuleFinder} is not required to be thread safe.

        * * @since 9 + * @spec JPMS */ public interface ModuleFinder { @@ -124,8 +126,8 @@ public interface ModuleFinder { * to find that module.

        * * @apiNote This is important to have for methods such as {@link - * Configuration#resolveRequiresAndUses resolveRequiresAndUses} that need - * to scan the module path to find modules that provide a specific service. + * Configuration#resolveAndBind resolveAndBind} that need to scan the + * module path to find modules that provide a specific service. * * @return The set of all module references that this finder locates * @@ -172,7 +174,8 @@ public interface ModuleFinder { } else { Path mlib = Paths.get(home, "modules"); if (Files.isDirectory(mlib)) { - return of(mlib); + // exploded build may be patched + return ModulePath.of(ModuleBootstrap.patcher(), mlib); } else { throw new InternalError("Unable to detect the run-time image"); } @@ -198,13 +201,9 @@ public interface ModuleFinder { * *

        If an element is a path to a directory of modules then each entry in * the directory is a packaged module or the top-level directory of an - * exploded module. The module finder's {@link #find(String) find} or - * {@link #findAll() findAll} methods throw {@link FindException} if a - * directory containing more than one module with the same name is - * encountered.

        - * - *

        If an element in the array is a path to a directory, and that - * directory contains a file named {@code module-info.class}, then the + * exploded module. It it an error if a directory contains more than one + * module with the same name. If an element is a path to a directory, and + * that directory contains a file named {@code module-info.class}, then the * directory is treated as an exploded module rather than a directory of * modules.

        * @@ -214,9 +213,8 @@ public interface ModuleFinder { * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release} * JAR file) is a modular JAR and is an explicit module. * A JAR file that does not have a {@code module-info.class} in the - * top-level directory is an {@link ModuleDescriptor#isAutomatic automatic} - * module. The {@link ModuleDescriptor} for an automatic module is created as - * follows: + * top-level directory is created as an automatic module. The components + * for the automatic module are derived as follows: * *
          * @@ -248,46 +246,48 @@ public interface ModuleFinder { * *
      • * - *
      • It {@link ModuleDescriptor#requires() requires} {@code - * java.base}.

      • - * - *
      • The set of packages in the module is derived from the names - * of non-directory entries in the JAR file. A candidate package name - * is derived from an entry using the characters up to, but not - * including, the last forward slash. All remaining forward slashes are - * replaced with dot ({@code "."}). If the resulting string is a valid - * Java identifier then it is assumed to be a package name. For example, - * if the JAR file contains an entry "{@code p/q/Foo.class}" then the - * package name derived is "{@code p.q}". All packages are {@link - * ModuleDescriptor#exports() exported}.

      • + *
      • The set of packages in the module is derived from the + * non-directory entries in the JAR file that have names ending in + * "{@code .class}". A candidate package name is derived from the name + * using the characters up to, but not including, the last forward slash. + * All remaining forward slashes are replaced with dot ({@code "."}). If + * the resulting string is a legal package name then it is assumed to be + * a package name. For example, if the JAR file contains the entry + * "{@code p/q/Foo.class}" then the package name derived is + * "{@code p.q}".

      • * *
      • The contents of entries starting with {@code * META-INF/services/} are assumed to be service configuration files * (see {@link java.util.ServiceLoader}). If the name of a file - * (that follows {@code META-INF/services/}) is a legal Java identifier - * then it is assumed to be the fully-qualified binary name of a - * service type. The entries in the file are assumed to be the - * fully-qualified binary names of provider classes.

      • + * (that follows {@code META-INF/services/}) is a legal class name + * then it is assumed to be the fully-qualified class name of a service + * type. The entries in the file are assumed to be the fully-qualified + * class names of provider classes.

        * *
      • If the JAR file has a {@code Main-Class} attribute in its - * main manifest then its value is the {@link + * main manifest then its value is the module {@link * ModuleDescriptor#mainClass() main class}.

      • * *
      * *

      If a {@code ModuleDescriptor} cannot be created (by means of the * {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an - * automatic module then {@code FindException} is thrown. This can arise, - * for example, when a legal Java identifier name cannot be derived from - * the file name of the JAR file or where the JAR file contains a {@code - * .class} in the top-level directory of the JAR file.

      + * automatic module then {@code FindException} is thrown. This can arise + * when a legal module name cannot be derived from the file name of the JAR + * file, where the JAR file contains a {@code .class} in the top-level + * directory of the JAR file, where an entry in a service configuration + * file is not a legal class name or its package name is not in the set of + * packages derived for the module, or where the module main class is not + * a legal class name or its package is not in the module.

      * *

      In addition to JAR files, an implementation may also support modules - * that are packaged in other implementation specific module formats. When - * a file is encountered that is not recognized as a packaged module then - * {@code FindException} is thrown. An implementation may choose to ignore - * some files, {@link java.nio.file.Files#isHidden hidden} files for - * example. Paths to files that do not exist are always ignored.

      + * that are packaged in other implementation specific module formats. If + * an element in the array specified to this method is a path to a directory + * of modules then entries in the directory that not recognized as modules + * are ignored. If an element in the array is a path to a packaged module + * that is not recognized then a {@code FindException} is thrown when the + * file is encountered. Paths to files that do not exist are always ignored. + *

      * *

      As with automatic modules, the contents of a packaged or exploded * module may need to be scanned in order to determine the packages @@ -325,7 +325,7 @@ public interface ModuleFinder { }; } - return new ModulePath(entries); + return ModulePath.of(entries); } /** diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java index d79d210edd0..c5a7b61c695 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java @@ -45,7 +45,7 @@ import java.util.stream.Stream; * module. A module reader is also intended to be used by {@code ClassLoader} * implementations that load classes and resources from modules.

      * - *

      A resource in a module is identified by a name that is a + *

      A resource in a module is identified by an abstract name that is a * '{@code /}'-separated path string. For example, module {@code java.base} may * have a resource "{@code java/lang/Object.class}" that, by convention, is the * class file for {@code java.lang.Object}.

      @@ -61,8 +61,18 @@ import java.util.stream.Stream; * open}, {@link #read read}, and {@link #list list} methods may throw {@code * SecurityException} if access is denied by the security manager.

      * + * @implSpec Implementations of {@code ModuleReader} should take great care + * when translating an abstract resource name to the location of a resource in + * a packaged module or on the file system. Implementations are advised to + * treat resource names with elements such as '{@code .}, '{@code ..}', + * elements containing file separators, or empty elements as "not found". More + * generally, if the resource name is not in the stream of elements that the + * {@code list} method returns then the resource should be treated as "not + * found" to avoid inconsistencies. + * * @see ModuleReference * @since 9 + * @spec JPMS */ public interface ModuleReader extends Closeable { @@ -148,6 +158,9 @@ public interface ModuleReader extends Closeable { * If an I/O error occurs or the module reader is closed * @throws SecurityException * If denied by the security manager + * @throws OutOfMemoryError + * If the resource is larger than {@code Integer.MAX_VALUE}, + * the maximum capacity of a byte buffer * * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain) */ diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java index 09a5acec219..54291e78dcc 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java @@ -44,6 +44,7 @@ import java.util.Optional; * @see ModuleFinder * @see ModuleReader * @since 9 + * @spec JPMS */ public abstract class ModuleReference { @@ -76,7 +77,7 @@ public abstract class ModuleReference { /** * Returns the location of this module's content, if known. * - *

      This URI, when present, is used as the {@linkplain + *

      This URI, when present, can be used as the {@linkplain * java.security.CodeSource#getLocation location} value of a {@link * java.security.CodeSource CodeSource} so that a module's classes can be * granted specific permissions when loaded by a {@link diff --git a/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java b/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java index fb14cfe8200..69cc71f3466 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * 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,10 +26,12 @@ package java.lang.module; /** - * Thrown when resolving a set of modules or binding fails. + * Thrown when resolving a set of modules, or resolving a set of modules with + * service binding, fails. * * @see Configuration * @since 9 + * @spec JPMS */ public class ResolutionException extends RuntimeException { private static final long serialVersionUID = -1031186845316729450L; diff --git a/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java b/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java index 05ef3c4dc1c..a3858ef6c13 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java +++ b/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java @@ -37,6 +37,7 @@ import java.util.Set; * module's content. * * @since 9 + * @spec JPMS * @see Configuration#modules() */ public final class ResolvedModule { diff --git a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java index d2aafdc5d87..1a44475b442 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java +++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,8 +49,8 @@ import jdk.internal.module.ModuleHashes; import jdk.internal.module.ModuleReferenceImpl; /** - * The resolver used by {@link Configuration#resolveRequires} and - * {@link Configuration#resolveRequiresAndUses}. + * The resolver used by {@link Configuration#resolve} and {@link + * Configuration#resolveAndBind}. * * @implNote The resolver is used at VM startup and so deliberately avoids * using lambda and stream usages in code paths used during startup. @@ -66,7 +66,19 @@ final class Resolver { // maps module name to module reference private final Map nameToReference = new HashMap<>(); + // module constraints on target platform + private String osName; + private String osArch; + private String osVersion; + String osName() { return osName; } + String osArch() { return osArch; } + String osVersion() { return osVersion; } + + /** + * @throws IllegalArgumentException if there are more than one parent and + * the constraints on the target platform conflict + */ Resolver(ModuleFinder beforeFinder, List parents, ModuleFinder afterFinder, @@ -75,15 +87,54 @@ final class Resolver { this.parents = parents; this.afterFinder = afterFinder; this.traceOutput = traceOutput; + + // record constraints on target platform, checking that they don't conflict + for (Configuration parent : parents) { + String value = parent.osName(); + if (value != null) { + if (osName == null) { + osName = value; + } else { + if (!value.equals(osName)) { + failParentConflict("Operating System", osName, value); + } + } + } + value = parent.osArch(); + if (value != null) { + if (osArch == null) { + osArch = value; + } else { + if (!value.equals(osArch)) { + failParentConflict("OS architecture", osArch, value); + } + } + } + value = parent.osVersion(); + if (value != null) { + if (osVersion == null) { + osVersion = value; + } else { + if (!value.equals(osVersion)) { + failParentConflict("OS version", osVersion, value); + } + } + } + } } + private void failParentConflict(String constraint, String s1, String s2) { + String msg = "Parents have conflicting constraints on target " + + constraint + ": " + s1 + ", " + s2; + throw new IllegalArgumentException(msg); + } /** * Resolves the given named modules. * * @throws ResolutionException */ - Resolver resolveRequires(Collection roots) { + Resolver resolve(Collection roots) { // create the visit stack to get us started Deque q = new ArrayDeque<>(); @@ -100,7 +151,7 @@ final class Resolver { mref = findWithAfterFinder(root); if (mref == null) { - fail("Module %s not found", root); + findFail("Module %s not found", root); } } @@ -109,8 +160,7 @@ final class Resolver { mref.location().ifPresent(uri -> trace(" (%s)", uri)); } - assert mref.descriptor().name().equals(root); - nameToReference.put(root, mref); + addFoundModule(mref); q.push(mref.descriptor()); } @@ -152,19 +202,19 @@ final class Resolver { mref = findWithAfterFinder(dn); if (mref == null) { - fail("Module %s not found, required by %s", - dn, descriptor.name()); + findFail("Module %s not found, required by %s", + dn, descriptor.name()); } } if (!nameToReference.containsKey(dn)) { - nameToReference.put(dn, mref); + addFoundModule(mref); q.offer(mref.descriptor()); resolved.add(mref.descriptor()); if (isTracing()) { trace("Module %s located, required by %s", - dn, descriptor.name()); + dn, descriptor.name()); mref.location().ifPresent(uri -> trace(" (%s)", uri)); } } @@ -181,7 +231,7 @@ final class Resolver { * Augments the set of resolved modules with modules induced by the * service-use relation. */ - Resolver resolveUses() { + Resolver bind() { // Scan the finders for all available service provider modules. As // java.base uses services then then module finders will be scanned @@ -246,7 +296,7 @@ final class Resolver { mref.location() .ifPresent(uri -> trace(" (%s)", uri)); } - nameToReference.put(pn, mref); + addFoundModule(mref); q.push(provider); } } @@ -263,6 +313,81 @@ final class Resolver { } + /** + * Add the module to the nameToReference map. Also check any constraints on + * the target platform with the constraints of other modules. + */ + private void addFoundModule(ModuleReference mref) { + ModuleDescriptor descriptor = mref.descriptor(); + nameToReference.put(descriptor.name(), mref); + + if (descriptor.osName().isPresent() + || descriptor.osArch().isPresent() + || descriptor.osVersion().isPresent()) + checkTargetConstraints(descriptor); + } + + /** + * Check that the module's constraints on the target platform do not + * conflict with the constraints of other modules resolved so far or + * modules in parent configurations. + */ + private void checkTargetConstraints(ModuleDescriptor descriptor) { + String value = descriptor.osName().orElse(null); + if (value != null) { + if (osName == null) { + osName = value; + } else { + if (!value.equals(osName)) { + failTargetConstraint(descriptor); + } + } + } + value = descriptor.osArch().orElse(null); + if (value != null) { + if (osArch == null) { + osArch = value; + } else { + if (!value.equals(osArch)) { + failTargetConstraint(descriptor); + } + } + } + value = descriptor.osVersion().orElse(null); + if (value != null) { + if (osVersion == null) { + osVersion = value; + } else { + if (!value.equals(osVersion)) { + failTargetConstraint(descriptor); + } + } + } + } + + private void failTargetConstraint(ModuleDescriptor md) { + String s1 = targetAsString(osName, osArch, osVersion); + String s2 = targetAsString(md); + findFail("Module %s has constraints on target platform that conflict" + + " with other modules: %s, %s", md.name(), s1, s2); + } + + private String targetAsString(ModuleDescriptor descriptor) { + String osName = descriptor.osName().orElse(null); + String osArch = descriptor.osArch().orElse(null); + String osVersion = descriptor.osVersion().orElse(null); + return targetAsString(osName, osArch, osVersion); + } + + private String targetAsString(String osName, String osArch, String osVersion) { + return new StringJoiner("-") + .add(Objects.toString(osName, "*")) + .add(Objects.toString(osArch, "*")) + .add(Objects.toString(osVersion, "*")) + .toString(); + } + + /** * Execute post-resolution checks and returns the module graph of resolved * modules as {@code Map}. The resolved modules will be in the given @@ -281,7 +406,6 @@ final class Resolver { if (check) { detectCycles(); - checkPlatformConstraints(); checkHashes(); } @@ -319,8 +443,7 @@ final class Resolver { if (!visited.contains(descriptor)) { boolean added = visitPath.add(descriptor); if (!added) { - throw new ResolutionException("Cycle detected: " + - cycleAsString(descriptor)); + resolveFail("Cycle detected: %s", cycleAsString(descriptor)); } for (ModuleDescriptor.Requires requires : descriptor.requires()) { String dn = requires.name(); @@ -353,86 +476,6 @@ final class Resolver { } - /** - * If there are platform specific modules then check that the OS name, - * architecture and version match. - * - * @apiNote This method does not currently check if the OS matches - * platform specific modules in parent configurations. - */ - private void checkPlatformConstraints() { - - // first module encountered that is platform specific - String savedModuleName = null; - String savedOsName = null; - String savedOsArch = null; - String savedOsVersion = null; - - for (ModuleReference mref : nameToReference.values()) { - ModuleDescriptor descriptor = mref.descriptor(); - - String osName = descriptor.osName().orElse(null); - String osArch = descriptor.osArch().orElse(null); - String osVersion = descriptor.osVersion().orElse(null); - - if (osName != null || osArch != null || osVersion != null) { - - if (savedModuleName == null) { - - savedModuleName = descriptor.name(); - savedOsName = osName; - savedOsArch = osArch; - savedOsVersion = osVersion; - - } else { - - boolean matches = platformMatches(osName, savedOsName) - && platformMatches(osArch, savedOsArch) - && platformMatches(osVersion, savedOsVersion); - - if (!matches) { - String s1 = platformAsString(savedOsName, - savedOsArch, - savedOsVersion); - - String s2 = platformAsString(osName, osArch, osVersion); - fail("Mismatching constraints on target platform: " - + savedModuleName + ": " + s1 - + ", " + descriptor.name() + ": " + s2); - } - - } - - } - } - - } - - /** - * Returns true if the s1 and s2 are equal or one of them is null. - */ - private boolean platformMatches(String s1, String s2) { - if (s1 == null || s2 == null) - return true; - else - return Objects.equals(s1, s2); - } - - /** - * Return a string that encodes the OS name/arch/version. - */ - private String platformAsString(String osName, - String osArch, - String osVersion) { - - return new StringJoiner("-") - .add(Objects.toString(osName, "*")) - .add(Objects.toString(osArch, "*")) - .add(Objects.toString(osVersion, "*")) - .toString(); - - } - /** * Checks the hashes in the module descriptor to ensure that they match * any recorded hashes. @@ -460,7 +503,7 @@ final class Resolver { continue; if (!(mref2 instanceof ModuleReferenceImpl)) { - fail("Unable to compute the hash of module %s", dn); + findFail("Unable to compute the hash of module %s", dn); } // skip checking the hash if the module has been patched @@ -469,11 +512,11 @@ final class Resolver { byte[] recordedHash = hashes.hashFor(dn); byte[] actualHash = other.computeHash(algorithm); if (actualHash == null) - fail("Unable to compute the hash of module %s", dn); + findFail("Unable to compute the hash of module %s", dn); if (!Arrays.equals(recordedHash, actualHash)) { - fail("Hash of %s (%s) differs to expected hash (%s)" + - " recorded in %s", dn, toHexString(actualHash), - toHexString(recordedHash), descriptor.name()); + findFail("Hash of %s (%s) differs to expected hash (%s)" + + " recorded in %s", dn, toHexString(actualHash), + toHexString(recordedHash), descriptor.name()); } } } @@ -694,37 +737,38 @@ final class Resolver { for (ResolvedModule endpoint : reads) { ModuleDescriptor descriptor2 = endpoint.descriptor(); - for (ModuleDescriptor.Exports export : descriptor2.exports()) { + if (descriptor2.isAutomatic()) { + // automatic modules read self and export all packages + if (descriptor2 != descriptor1){ + for (String source : descriptor2.packages()) { + ModuleDescriptor supplier + = packageToExporter.putIfAbsent(source, descriptor2); - if (export.isQualified()) { - if (!export.targets().contains(descriptor1.name())) - continue; - } - - // source is exported to descriptor2 - String source = export.source(); - ModuleDescriptor other - = packageToExporter.putIfAbsent(source, descriptor2); - - if (other != null && other != descriptor2) { - // package might be local to descriptor1 - if (other == descriptor1) { - fail("Module %s contains package %s" - + ", module %s exports package %s to %s", - descriptor1.name(), - source, - descriptor2.name(), - source, - descriptor1.name()); - } else { - fail("Modules %s and %s export package %s to module %s", - descriptor2.name(), - other.name(), - source, - descriptor1.name()); + // descriptor2 and 'supplier' export source to descriptor1 + if (supplier != null) { + failTwoSuppliers(descriptor1, source, descriptor2, supplier); + } } } + } else { + for (ModuleDescriptor.Exports export : descriptor2.exports()) { + if (export.isQualified()) { + if (!export.targets().contains(descriptor1.name())) + continue; + } + + // source is exported by descriptor2 + String source = export.source(); + ModuleDescriptor supplier + = packageToExporter.putIfAbsent(source, descriptor2); + + // descriptor2 and 'supplier' export source to descriptor1 + if (supplier != null) { + failTwoSuppliers(descriptor1, source, descriptor2, supplier); + } + } + } } @@ -735,8 +779,8 @@ final class Resolver { for (String service : descriptor1.uses()) { String pn = packageName(service); if (!packageToExporter.containsKey(pn)) { - fail("Module %s does not read a module that exports %s", - descriptor1.name(), pn); + resolveFail("Module %s does not read a module that exports %s", + descriptor1.name(), pn); } } @@ -744,15 +788,8 @@ final class Resolver { for (ModuleDescriptor.Provides provides : descriptor1.provides()) { String pn = packageName(provides.service()); if (!packageToExporter.containsKey(pn)) { - fail("Module %s does not read a module that exports %s", - descriptor1.name(), pn); - } - - for (String provider : provides.providers()) { - if (!packages.contains(packageName(provider))) { - fail("Provider %s not in module %s", - provider, descriptor1.name()); - } + resolveFail("Module %s does not read a module that exports %s", + descriptor1.name(), pn); } } @@ -762,6 +799,42 @@ final class Resolver { } + /** + * Fail because a module in the configuration exports the same package to + * a module that reads both. This includes the case where a module M + * containing a package p reads another module that exports p to at least + * module M. + */ + private void failTwoSuppliers(ModuleDescriptor descriptor, + String source, + ModuleDescriptor supplier1, + ModuleDescriptor supplier2) { + + if (supplier2 == descriptor) { + ModuleDescriptor tmp = supplier1; + supplier1 = supplier2; + supplier2 = tmp; + } + + if (supplier1 == descriptor) { + resolveFail("Module %s contains package %s" + + ", module %s exports package %s to %s", + descriptor.name(), + source, + supplier2.name(), + source, + descriptor.name()); + } else { + resolveFail("Modules %s and %s export package %s to module %s", + supplier1.name(), + supplier2.name(), + source, + descriptor.name()); + } + + } + + /** * Find a module of the given name in the parent configurations */ @@ -779,24 +852,16 @@ final class Resolver { * Invokes the beforeFinder to find method to find the given module. */ private ModuleReference findWithBeforeFinder(String mn) { - try { - return beforeFinder.find(mn).orElse(null); - } catch (FindException e) { - // unwrap - throw new ResolutionException(e.getMessage(), e.getCause()); - } + + return beforeFinder.find(mn).orElse(null); + } /** * Invokes the afterFinder to find method to find the given module. */ private ModuleReference findWithAfterFinder(String mn) { - try { - return afterFinder.find(mn).orElse(null); - } catch (FindException e) { - // unwrap - throw new ResolutionException(e.getMessage(), e.getCause()); - } + return afterFinder.find(mn).orElse(null); } /** @@ -804,34 +869,27 @@ final class Resolver { * and after ModuleFinders. */ private Set findAll() { - try { + Set beforeModules = beforeFinder.findAll(); + Set afterModules = afterFinder.findAll(); - Set beforeModules = beforeFinder.findAll(); - Set afterModules = afterFinder.findAll(); + if (afterModules.isEmpty()) + return beforeModules; - if (afterModules.isEmpty()) - return beforeModules; + if (beforeModules.isEmpty() + && parents.size() == 1 + && parents.get(0) == Configuration.empty()) + return afterModules; - if (beforeModules.isEmpty() - && parents.size() == 1 - && parents.get(0) == Configuration.empty()) - return afterModules; - - Set result = new HashSet<>(beforeModules); - for (ModuleReference mref : afterModules) { - String name = mref.descriptor().name(); - if (!beforeFinder.find(name).isPresent() - && findInParent(name) == null) { - result.add(mref); - } + Set result = new HashSet<>(beforeModules); + for (ModuleReference mref : afterModules) { + String name = mref.descriptor().name(); + if (!beforeFinder.find(name).isPresent() + && findInParent(name) == null) { + result.add(mref); } - - return result; - - } catch (FindException e) { - // unwrap - throw new ResolutionException(e.getMessage(), e.getCause()); } + + return result; } /** @@ -842,10 +900,18 @@ final class Resolver { return (index == -1) ? "" : cn.substring(0, index); } + /** + * Throw FindException with the given format string and arguments + */ + private static void findFail(String fmt, Object ... args) { + String msg = String.format(fmt, args); + throw new FindException(msg); + } + /** * Throw ResolutionException with the given format string and arguments */ - private static void fail(String fmt, Object ... args) { + private static void resolveFail(String fmt, Object ... args) { String msg = String.format(fmt, args); throw new ResolutionException(msg); } diff --git a/jdk/src/java.base/share/classes/java/lang/module/package-info.java b/jdk/src/java.base/share/classes/java/lang/module/package-info.java index f641638cb2c..1d830079cab 100644 --- a/jdk/src/java.base/share/classes/java/lang/module/package-info.java +++ b/jdk/src/java.base/share/classes/java/lang/module/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,112 @@ * Classes to support module descriptors and creating configurations of modules * by means of resolution and service binding. * + *

      Resolution

      + * + *

      Resolution is the process of computing the transitive closure of a set + * of root modules over a set of observable modules by resolving the + * dependences expressed by {@link + * java.lang.module.ModuleDescriptor.Requires requires} clauses. + * The dependence graph is augmented with edges that take account of + * implicitly declared dependences ({@code requires transitive}) to create a + * readability graph. The result of resolution is a {@link + * java.lang.module.Configuration Configuration} that encapsulates the + * readability graph.

      + * + *

      As an example, suppose we have the following observable modules:

      + *
       {@code
      + *     module m1 { requires m2; }
      + *     module m2 { requires transitive m3; }
      + *     module m3 { }
      + *     module m4 { }
      + * } 
      + * + *

      If the module {@code m1} is resolved then the resulting configuration + * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in + * its readability graph are:

      + *
       {@code
      + *     m1 --> m2  (meaning m1 reads m2)
      + *     m1 --> m3
      + *     m2 --> m3
      + * } 
      + * + *

      Resolution is an additive process. When computing the transitive closure + * then the dependence relation may include dependences on modules in {@link + * java.lang.module.Configuration#parents() parent} configurations. The result + * is a relative configuration that is relative to one or more parent + * configurations and where the readability graph may have edges from modules + * in the configuration to modules in parent configurations.

      + * + *

      As an example, suppose we have the following observable modules:

      + *
       {@code
      + *     module m1 { requires m2; requires java.xml; }
      + *     module m2 { }
      + * } 
      + * + *

      If module {@code m1} is resolved with the configuration for the {@link + * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting + * configuration contains two modules ({@code m1}, {@code m2}). The edges in + * its readability graph are: + *

       {@code
      + *     m1 --> m2
      + *     m1 --> java.xml
      + * } 
      + * where module {@code java.xml} is in the parent configuration. For + * simplicity, this example omits the implicitly declared dependence on the + * {@code java.base} module. + * + *

      Requires clauses that are "{@code requires static}" express an optional + * dependence (except at compile-time). If a module declares that it + * "{@code requires static M}" then resolution does not search the observable + * modules for "{@code M}". However, if "{@code M}" is resolved (because resolution + * resolves a module that requires "{@code M}" without the {@link + * java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC static} modifier) + * then the readability graph will contain read edges for each module that + * "{@code requires static M}".

      + * + *

      {@link java.lang.module.ModuleDescriptor#isAutomatic() Automatic} modules + * receive special treatment during resolution. Each automatic module is resolved + * so that it reads all other modules in the configuration and all parent + * configurations. Each automatic module is also resolved as if it + * "{@code requires transitive}" all other automatic modules in the configuration + * (and all automatic modules in parent configurations).

      + * + *

      Service binding

      + * + *

      Service binding is the process of augmenting a graph of resolved modules + * from the set of observable modules induced by the service-use dependence + * ({@code uses} and {@code provides} clauses). Any module that was not + * previously in the graph requires resolution to compute its transitive + * closure. Service binding is an iterative process in that adding a module + * that satisfies some service-use dependence may introduce new service-use + * dependences.

      + * + *

      Suppose we have the following observable modules:

      + *
       {@code
      + *     module m1 { exports p; uses p.S; }
      + *     module m2 { requires m1; provides p.S with p2.S2; }
      + *     module m3 { requires m1; requires m4; provides p.S with p3.S3; }
      + *     module m4 { }
      + * } 
      + * + *

      If the module {@code m1} is resolved then the resulting graph of modules + * has one module ({@code m1}). If the graph is augmented with modules induced + * by the service-use dependence relation then the configuration will contain + * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in + * its readability graph are:

      + *
       {@code
      + *     m2 --> m1
      + *     m3 --> m1
      + *     m3 --> m4
      + * } 
      + *

      The edges in the conceptual service-use graph are:

      + *
       {@code
      + *     m1 --> m2  (meaning m1 uses a service that is provided by m2)
      + *     m1 --> m3
      + * } 
      + * + *

      General Exceptions

      + * *

      Unless otherwise noted, passing a {@code null} argument to a constructor * or method of any class or interface in this package will cause a {@link * java.lang.NullPointerException NullPointerException} to be thrown. Additionally, @@ -34,6 +140,7 @@ * will cause a {@code NullPointerException}, unless otherwise specified.

      * * @since 9 + * @spec JPMS */ package java.lang.module; diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java index f585b476504..503ce8dfb1e 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,38 +28,44 @@ package java.lang.reflect; import java.lang.annotation.Annotation; import java.security.AccessController; -import jdk.internal.misc.VM; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.reflect.ReflectionFactory; -import sun.security.action.GetPropertyAction; /** - * The AccessibleObject class is the base class for Field, Method and - * Constructor objects. It provides the ability to flag a reflected - * object as suppressing default Java language access control checks - * when it is used. The access checks -- module boundaries, - * public, default (package) access, protected, and private members -- - * are performed when Fields, Methods or Constructors are used to set - * or get fields, to invoke methods or to create and initialize new - * instances of classes, respectively. Unlike access control specified - * in the The Java™ Language Specification and - * The Java Virtual Machine Specification, access checks - * with reflected objects assume {@link Module#canRead readability}. + * The {@code AccessibleObject} class is the base class for {@code Field}, + * {@code Method}, and {@code Constructor} objects (known as reflected + * objects). It provides the ability to flag a reflected object as + * suppressing checks for Java language access control when it is used. This + * permits sophisticated applications with sufficient privilege, such as Java + * Object Serialization or other persistence mechanisms, to manipulate objects + * in a manner that would normally be prohibited. * - *

      Setting the {@code accessible} flag in a reflected object - * permits sophisticated applications with sufficient privilege, such - * as Java Object Serialization or other persistence mechanisms, to - * manipulate objects in a manner that would normally be prohibited. + *

      Java language access control prevents use of private members outside + * their class; package access members outside their package; protected members + * outside their package or subclasses; and public members outside their + * module unless they are declared in an {@link Module#isExported(String,Module) + * exported} package and the user {@link Module#canRead reads} their module. By + * default, Java language access control is enforced (with one variation) when + * {@code Field}s, {@code Method}s, or {@code Constructor}s are used to get or + * set fields, to invoke methods, or to create and initialize new instances of + * classes, respectively. Every reflected object checks that the code using it + * is in an appropriate class, package, or module.

      * - *

      By default, a reflected object is not accessible. + *

      The one variation from Java language access control is that the checks + * by reflected objects assume readability. That is, the module containing + * the use of a reflected object is assumed to read the module in which + * the underlying field, method, or constructor is declared.

      * - * @see Field - * @see Method - * @see Constructor - * @see ReflectPermission + *

      Whether the checks for Java language access control can be suppressed + * (and thus, whether access can be enabled) depends on whether the reflected + * object corresponds to a member in an exported or open package + * (see {@link #setAccessible(boolean)}).

      * + * @jls 6.6 Access Control * @since 1.2 + * @revised 9 + * @spec JPMS */ public class AccessibleObject implements AnnotatedElement { @@ -78,15 +84,11 @@ public class AccessibleObject implements AnnotatedElement { /** * Convenience method to set the {@code accessible} flag for an - * array of objects with a single security check (for efficiency). + * array of reflected objects with a single security check (for efficiency). * - *

      This method cannot be used to enable access to an object that is a - * {@link Member member} of a class in a different module to the caller and - * where the class is in a package that is not exported to the caller's - * module. Additionally, if the member is non-public or its declaring - * class is non-public, then this method can only be used to enable access - * if the package is {@link Module#isOpen(String,Module) open} to at least - * the caller's module. + *

      This method may be used to enable access to all reflected objects in + * the array when access to each reflected object can be enabled as + * specified by {@link #setAccessible(boolean) setAccessible(boolean)}.

      * *

      If there is a security manager, its * {@code checkPermission} method is first called with a @@ -99,10 +101,15 @@ public class AccessibleObject implements AnnotatedElement { * @param array the array of AccessibleObjects * @param flag the new value for the {@code accessible} flag * in each object - * @throws InaccessibleObjectException if access cannot be enabled - * @throws SecurityException if the request is denied. + * @throws InaccessibleObjectException if access cannot be enabled for all + * objects in the array + * @throws SecurityException if the request is denied by the security manager + * or an element in the array is a constructor for {@code + * java.lang.Class} * @see SecurityManager#checkPermission * @see ReflectPermission + * @revised 9 + * @spec JPMS */ @CallerSensitive public static void setAccessible(AccessibleObject[] array, boolean flag) { @@ -120,41 +127,143 @@ public class AccessibleObject implements AnnotatedElement { } /** - * Set the {@code accessible} flag for this object to + * Set the {@code accessible} flag for this reflected object to * the indicated boolean value. A value of {@code true} indicates that - * the reflected object should suppress Java language access - * checking when it is used. A value of {@code false} indicates - * that the reflected object should enforce Java language access checks - * while assuming readability (as noted in the class description). + * the reflected object should suppress checks for Java language access + * control when it is used. A value of {@code false} indicates that + * the reflected object should enforce checks for Java language access + * control when it is used, with the variation noted in the class description. * - *

      This method cannot be used to enable access to an object that is a - * {@link Member member} of a class in a different module to the caller and - * where the class is in a package that is not exported to the caller's - * module. Additionally, if the member is non-public or its declaring - * class is non-public, then this method can only be used to enable access - * if the package is {@link Module#isOpen(String,Module) open} to at least - * the caller's module. + *

      This method may be used by a caller in class {@code C} to enable + * access to a {@link Member member} of {@link Member#getDeclaringClass() + * declaring class} {@code D} if any of the following hold:

      * - *

      If there is a security manager, its + *

        + *
      • {@code C} and {@code D} are in the same module.
      • + * + *
      • The member is {@code public} and {@code D} is {@code public} in + * a package that the module containing {@code D} {@link + * Module#isExported(String,Module) exports} to at least the module + * containing {@code C}.
      • + * + *
      • The member is {@code protected} {@code static}, {@code D} is + * {@code public} in a package that the module containing {@code D} + * exports to at least the module containing {@code C}, and {@code C} + * is a subclass of {@code D}.
      • + * + *
      • {@code D} is in a package that the module containing {@code D} + * {@link Module#isOpen(String,Module) opens} to at least the module + * containing {@code C}. + * All packages in unnamed and open modules are open to all modules and + * so this method always succeeds when {@code D} is in an unnamed or + * open module.
      • + *
      + * + *

      This method cannot be used to enable access to private members, + * members with default (package) access, protected instance members, or + * protected constructors when the declaring class is in a different module + * to the caller and the package containing the declaring class is not open + * to the caller's module.

      + * + *

      If there is a security manager, its * {@code checkPermission} method is first called with a * {@code ReflectPermission("suppressAccessChecks")} permission. * * @param flag the new value for the {@code accessible} flag * @throws InaccessibleObjectException if access cannot be enabled - * @throws SecurityException if the request is denied - * @see SecurityManager#checkPermission - * @see ReflectPermission + * @throws SecurityException if the request is denied by the security manager + * @see #trySetAccessible * @see java.lang.invoke.MethodHandles#privateLookupIn + * @revised 9 + * @spec JPMS */ public void setAccessible(boolean flag) { AccessibleObject.checkPermission(); setAccessible0(flag); } - void setAccessible0(boolean flag) { + /** + * Sets the accessible flag and returns the new value + */ + boolean setAccessible0(boolean flag) { this.override = flag; + return flag; } + /** + * Set the {@code accessible} flag for this reflected object to {@code true} + * if possible. This method sets the {@code accessible} flag, as if by + * invoking {@link #setAccessible(boolean) setAccessible(true)}, and returns + * the possibly-updated value for the {@code accessible} flag. If access + * cannot be enabled, i.e. the checks or Java language access control cannot + * be suppressed, this method returns {@code false} (as opposed to {@code + * setAccessible(true)} throwing {@code InaccessibleObjectException} when + * it fails). + * + *

      This method is a no-op if the {@code accessible} flag for + * this reflected object is {@code true}. + * + *

      For example, a caller can invoke {@code trySetAccessible} + * on a {@code Method} object for a private instance method + * {@code p.T::privateMethod} to suppress the checks for Java language access + * control when the {@code Method} is invoked. + * If {@code p.T} class is in a different module to the caller and + * package {@code p} is open to at least the caller's module, + * the code below successfully sets the {@code accessible} flag + * to {@code true}. + * + *

      +     * {@code
      +     *     p.T obj = ....;  // instance of p.T
      +     *     :
      +     *     Method m = p.T.class.getDeclaredMethod("privateMethod");
      +     *     if (m.trySetAccessible()) {
      +     *         m.invoke(obj);
      +     *     } else {
      +     *         // package p is not opened to the caller to access private member of T
      +     *         ...
      +     *     }
      +     * }
      + * + *

      If there is a security manager, its {@code checkPermission} method + * is first called with a {@code ReflectPermission("suppressAccessChecks")} + * permission.

      + * + * @return {@code true} if the {@code accessible} flag is set to {@code true}; + * {@code false} if access cannot be enabled. + * @throws SecurityException if the request is denied by the security manager + * + * @since 9 + * @spec JPMS + * @see java.lang.invoke.MethodHandles#privateLookupIn + */ + @CallerSensitive + public final boolean trySetAccessible() { + AccessibleObject.checkPermission(); + + if (override == true) return true; + + // if it's not a Constructor, Method, Field then no access check + if (!Member.class.isInstance(this)) { + return setAccessible0(true); + } + + // does not allow to suppress access check for Class's constructor + Class declaringClass = ((Member) this).getDeclaringClass(); + if (declaringClass == Class.class && this instanceof Constructor) { + return false; + } + + if (checkCanSetAccessible(Reflection.getCallerClass(), + declaringClass, + false)) { + return setAccessible0(true); + } else { + return false; + } + } + + /** * If the given AccessibleObject is a {@code Constructor}, {@code Method} * or {@code Field} then checks that its declaring class is in a package @@ -164,22 +273,29 @@ public class AccessibleObject implements AnnotatedElement { // do nothing, needs to be overridden by Constructor, Method, Field } + void checkCanSetAccessible(Class caller, Class declaringClass) { + checkCanSetAccessible(caller, declaringClass, true); + } + + private boolean checkCanSetAccessible(Class caller, + Class declaringClass, + boolean throwExceptionIfDenied) { Module callerModule = caller.getModule(); Module declaringModule = declaringClass.getModule(); - if (callerModule == declaringModule) return; - if (callerModule == Object.class.getModule()) return; - if (!declaringModule.isNamed()) return; + if (callerModule == declaringModule) return true; + if (callerModule == Object.class.getModule()) return true; + if (!declaringModule.isNamed()) return true; // package is open to caller String pn = packageName(declaringClass); if (declaringModule.isOpen(pn, callerModule)) { - printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule); - return; + dumpStackIfOpenedReflectively(declaringModule, pn, callerModule); + return true; } - // package is exported to caller and class/member is public + // package is exported to caller boolean isExported = declaringModule.isExported(pn, callerModule); boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); int modifiers; @@ -188,48 +304,72 @@ public class AccessibleObject implements AnnotatedElement { } else { modifiers = ((Field) this).getModifiers(); } - boolean isMemberPublic = Modifier.isPublic(modifiers); - if (isExported && isClassPublic && isMemberPublic) { - printStackTraceIfExportedReflectively(declaringModule, pn, callerModule); - return; + if (isExported && isClassPublic) { + + // member is public + if (Modifier.isPublic(modifiers)) { + dumpStackIfExportedReflectively(declaringModule, pn, callerModule); + return true; + } + + // member is protected-static + if (Modifier.isProtected(modifiers) + && Modifier.isStatic(modifiers) + && isSubclassOf(caller, declaringClass)) { + dumpStackIfExportedReflectively(declaringModule, pn, callerModule); + return true; + } } - // not accessible - String msg = "Unable to make "; - if (this instanceof Field) - msg += "field "; - msg += this + " accessible: " + declaringModule + " does not \""; - if (isClassPublic && isMemberPublic) - msg += "exports"; - else - msg += "opens"; - msg += " " + pn + "\" to " + callerModule; - InaccessibleObjectException e = new InaccessibleObjectException(msg); - if (Reflection.printStackTraceWhenAccessFails()) { - e.printStackTrace(System.err); + if (throwExceptionIfDenied) { + // not accessible + String msg = "Unable to make "; + if (this instanceof Field) + msg += "field "; + msg += this + " accessible: " + declaringModule + " does not \""; + if (isClassPublic && Modifier.isPublic(modifiers)) + msg += "exports"; + else + msg += "opens"; + msg += " " + pn + "\" to " + callerModule; + InaccessibleObjectException e = new InaccessibleObjectException(msg); + if (Reflection.printStackTraceWhenAccessFails()) { + e.printStackTrace(System.err); + } + throw e; } - throw e; + return false; } - private void printStackTraceIfOpenedReflectively(Module module, - String pn, - Module other) { - printStackTraceIfExposedReflectively(module, pn, other, true); + private boolean isSubclassOf(Class queryClass, Class ofClass) { + while (queryClass != null) { + if (queryClass == ofClass) { + return true; + } + queryClass = queryClass.getSuperclass(); + } + return false; } - private void printStackTraceIfExportedReflectively(Module module, - String pn, - Module other) { - printStackTraceIfExposedReflectively(module, pn, other, false); + private void dumpStackIfOpenedReflectively(Module module, + String pn, + Module other) { + dumpStackIfExposedReflectively(module, pn, other, true); } - private void printStackTraceIfExposedReflectively(Module module, - String pn, - Module other, - boolean open) + private void dumpStackIfExportedReflectively(Module module, + String pn, + Module other) { + dumpStackIfExposedReflectively(module, pn, other, false); + } + + private void dumpStackIfExposedReflectively(Module module, + String pn, + Module other, + boolean open) { if (Reflection.printStackTraceWhenAccessSucceeds() - && !module.isStaticallyExportedOrOpen(pn, other, open)) + && !module.isStaticallyExportedOrOpen(pn, other, open)) { String msg = other + " allowed to invoke setAccessible on "; if (this instanceof Field) @@ -256,14 +396,99 @@ public class AccessibleObject implements AnnotatedElement { } /** - * Get the value of the {@code accessible} flag for this object. + * Get the value of the {@code accessible} flag for this reflected object. * * @return the value of the object's {@code accessible} flag + * + * @deprecated + * This method is deprecated because its name hints that it checks + * if the reflected object is accessible when it actually indicates + * if the checks for Java language access control are suppressed. + * This method may return {@code false} on a reflected object that is + * accessible to the caller. To test if this reflected object is accessible, + * it should use {@link #canAccess(Object)}. + * + * @revised 9 */ + @Deprecated(since="9") public boolean isAccessible() { return override; } + /** + * Test if the caller can access this reflected object. If this reflected + * object corresponds to an instance method or field then this method tests + * if the caller can access the given {@code obj} with the reflected object. + * For instance methods or fields then the {@code obj} argument must be an + * instance of the {@link Member#getDeclaringClass() declaring class}. For + * static members and constructors then {@code obj} must be {@code null}. + * + *

      This method returns {@code true} if the {@code accessible} flag + * is set to {@code true}, i.e. the checks for Java language access control + * are suppressed, or if the caller can access the member as + * specified in The Java™ Language Specification, + * with the variation noted in the class description.

      + * + * @param obj an instance object of the declaring class of this reflected + * object if it is an instance method or field + * + * @return {@code true} if the caller can access this reflected object. + * + * @throws IllegalArgumentException + *
        + *
      • if this reflected object is a static member or constructor and + * the given {@code obj} is non-{@code null}, or
      • + *
      • if this reflected object is an instance method or field + * and the given {@code obj} is {@code null} or of type + * that is not a subclass of the {@link Member#getDeclaringClass() + * declaring class} of the member.
      • + *
      + * + * @since 9 + * @spec JPMS + * @jls 6.6 Access Control + * @see #trySetAccessible + * @see #setAccessible(boolean) + */ + @CallerSensitive + public final boolean canAccess(Object obj) { + if (!Member.class.isInstance(this)) { + return override; + } + + Class declaringClass = ((Member) this).getDeclaringClass(); + int modifiers = ((Member) this).getModifiers(); + if (!Modifier.isStatic(modifiers) && + (this instanceof Method || this instanceof Field)) { + if (obj == null) { + throw new IllegalArgumentException("null object for " + this); + } + // if this object is an instance member, the given object + // must be a subclass of the declaring class of this reflected object + if (!declaringClass.isAssignableFrom(obj.getClass())) { + throw new IllegalArgumentException("object is not an instance of " + + declaringClass.getName()); + } + } else if (obj != null) { + throw new IllegalArgumentException("non-null object for " + this); + } + + // access check is suppressed + if (override) return true; + + Class caller = Reflection.getCallerClass(); + Class targetClass; + if (this instanceof Constructor) { + targetClass = declaringClass; + } else { + targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass(); + } + return Reflection.verifyMemberAccess(caller, + declaringClass, + targetClass, + modifiers); + } + /** * Constructor: only used by the Java Virtual Machine. */ diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java index f64e84f7f37..968e3f30af4 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -168,6 +168,13 @@ public final class Constructor extends Executable { * is true.

      * * @param flag {@inheritDoc} + * + * @throws InaccessibleObjectException {@inheritDoc} + * @throws SecurityException if the request is denied by the security manager + * or this is a constructor for {@code java.lang.Class} + * + * @since 9 + * @spec JPMS */ @Override @CallerSensitive diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java index 05b71785ffa..ef892714b03 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Field.java @@ -158,6 +158,10 @@ class Field extends AccessibleObject implements Member { return res; } + /** + * @throws InaccessibleObjectException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ @Override @CallerSensitive public void setAccessible(boolean flag) { diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java b/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java index 34db5150f85..b03d449fecc 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java @@ -30,6 +30,7 @@ package java.lang.reflect; * * @see AccessibleObject#setAccessible(boolean) * @since 9 + * @spec JPMS */ public class InaccessibleObjectException extends RuntimeException { diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java index 9eaf90d0ca8..d6d89980aae 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java @@ -56,20 +56,19 @@ import sun.security.util.SecurityConstants; /** * A layer of modules in the Java virtual machine. * - *

      A layer is created from a graph of modules that is the {@link - * Configuration} and a function that maps each module to a {@link ClassLoader}. + *

      A layer is created from a graph of modules in a {@link Configuration} + * and a function that maps each module to a {@link ClassLoader}. * Creating a layer informs the Java virtual machine about the classes that - * may be loaded from modules so that the Java virtual machine knows which - * module that each class is a member of. Each layer, except the {@link - * #empty() empty} layer, has at least one {@link #parents() parent}.

      + * may be loaded from the modules so that the Java virtual machine knows which + * module that each class is a member of.

      * *

      Creating a layer creates a {@link Module} object for each {@link * ResolvedModule} in the configuration. For each resolved module that is * {@link ResolvedModule#reads() read}, the {@code Module} {@link * Module#canRead reads} the corresponding run-time {@code Module}, which may - * be in the same layer or a parent layer. The {@code Module} {@link - * Module#isExported(String) exports} the packages described by its {@link - * ModuleDescriptor}.

      + * be in the same layer or a {@link #parents() parent} layer. The {@code Module} + * {@link Module#isExported(String) exports} and {@link Module#isOpen(String) + * opens} the packages described by its {@link ModuleDescriptor}.

      * *

      The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods @@ -80,7 +79,7 @@ import sun.security.util.SecurityConstants; * a function specified to the method. Each of these methods has an instance * and static variant. The instance methods create a layer with the receiver * as the parent layer. The static methods are for more advanced cases where - * there can be more than one parent layer or a {@link Layer.Controller + * there can be more than one parent layer or where a {@link Layer.Controller * Controller} is needed to control modules in the layer.

      * *

      A Java virtual machine has at least one non-empty layer, the {@link @@ -93,9 +92,8 @@ import sun.security.util.SecurityConstants; * the {@link #parents() parent} when creating additional layers.

      * *

      As when creating a {@code Configuration}, - * {@link ModuleDescriptor#isAutomatic() automatic} modules receive - * special - * treatment when creating a layer. An automatic module is created in the + * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special + * treatment when creating a layer. An automatic module is created in the * Java virtual machine as a {@code Module} that reads every unnamed {@code * Module} in the Java virtual machine.

      * @@ -115,8 +113,7 @@ import sun.security.util.SecurityConstants; * * Layer parent = Layer.boot(); * - * Configuration cf = parent.configuration() - * .resolveRequires(finder, ModuleFinder.of(), Set.of("myapp")); + * Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp")); * * ClassLoader scl = ClassLoader.getSystemClassLoader(); * @@ -126,6 +123,7 @@ import sun.security.util.SecurityConstants; * } * * @since 9 + * @spec JPMS * @see Module#getLayer() */ @@ -168,10 +166,15 @@ public final class Layer { * module layers return a {@code Controller} that can be used to control * modules in the layer. * + *

      Unless otherwise specified, passing a {@code null} argument to a + * method in this class causes a {@link NullPointerException + * NullPointerException} to be thrown.

      + * * @apiNote Care should be taken with {@code Controller} objects, they * should never be shared with untrusted code. * * @since 9 + * @spec JPMS */ public static final class Controller { private final Layer layer; @@ -281,10 +284,8 @@ public final class Layer { * If the parent of the given configuration is not the configuration * for this layer * @throws LayerInstantiationException - * If all modules cannot be defined to the same class loader for any - * of the reasons listed above or the layer cannot be created because - * the configuration contains a module named "{@code java.base}" or - * a module with a package name starting with "{@code java.}" + * If the layer cannot be created for any of the reasons specified + * by the static {@code defineModulesWithOneLoader} method * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -325,9 +326,8 @@ public final class Layer { * If the parent of the given configuration is not the configuration * for this layer * @throws LayerInstantiationException - * If the layer cannot be created because the configuration contains - * a module named "{@code java.base}" or a module with a package - * name starting with "{@code java.}" + * If the layer cannot be created for any of the reasons specified + * by the static {@code defineModulesWithManyLoaders} method * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -365,14 +365,8 @@ public final class Layer { * If the parent of the given configuration is not the configuration * for this layer * @throws LayerInstantiationException - * If creating the {@code Layer} fails for any of the reasons - * listed above, the layer cannot be created because the - * configuration contains a module named "{@code java.base}", - * a module with a package name starting with "{@code java.}" is - * mapped to a class loader other than the {@link - * ClassLoader#getPlatformClassLoader() platform class loader}, - * or the function to map a module name to a class loader returns - * {@code null} + * If the layer cannot be created for any of the reasons specified + * by the static {@code defineModules} method * @throws SecurityException * If {@code RuntimePermission("getClassLoader")} is denied by * the security manager @@ -396,7 +390,6 @@ public final class Layer { * exported to one or more of the modules in this layer. The class * loader delegates to the class loader of the module, throwing {@code * ClassNotFoundException} if not found by that class loader. - * * When {@code loadClass} is invoked to load classes that do not map to a * module then it delegates to the parent class loader.

      * @@ -414,6 +407,10 @@ public final class Layer { * *
    * + *

    In addition, a layer cannot be created if the configuration contains + * a module named "{@code java.base}" or a module with a package name + * starting with "{@code java.}".

    + * *

    If there is a security manager then the class loader created by * this method will load classes and resources with privileges that are * restricted by the calling context of this method.

    @@ -433,9 +430,7 @@ public final class Layer { * the parent layers, including order * @throws LayerInstantiationException * If all modules cannot be defined to the same class loader for any - * of the reasons listed above or the layer cannot be created because - * the configuration contains a module named "{@code java.base}" or - * a module with a package name starting with "{@code java.}" + * of the reasons listed above * @throws SecurityException * If {@code RuntimePermission("createClassLoader")} or * {@code RuntimePermission("getClassLoader")} is denied by @@ -480,7 +475,6 @@ public final class Layer { * module in a parent layer. The class loader delegates to the class loader * of the module, throwing {@code ClassNotFoundException} if not found by * that class loader. - * * When {@code loadClass} is invoked to load classes that do not map to a * module then it delegates to the parent class loader.

    * @@ -533,15 +527,19 @@ public final class Layer { /** * Creates a new layer by defining the modules in the given {@code - * Configuration} to the Java virtual machine. - * Each module is mapped, by name, to its class loader by means of the - * given function. The class loader delegation implemented by these class - * loaders must respect module readability. The class loaders should be + * Configuration} to the Java virtual machine. The given function maps each + * module in the configuration, by name, to a class loader. Creating the + * layer informs the Java virtual machine about the classes that may be + * loaded so that the Java virtual machine knows which module that each + * class is a member of. + * + *

    The class loader delegation implemented by the class loaders must + * respect module readability. The class loaders should be * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to * avoid deadlocks during class loading. In addition, the entity creating - * a new layer with this method should arrange that the class loaders are + * a new layer with this method should arrange that the class loaders be * ready to load from these modules before there are any attempts to load - * classes or resources. + * classes or resources.

    * *

    Creating a {@code Layer} can fail for the following reasons:

    * @@ -558,6 +556,13 @@ public final class Layer { * *
* + *

In addition, a layer cannot be created if the configuration contains + * a module named "{@code java.base}", a configuration contains a module + * with a package name starting with "{@code java.}" is mapped to a class + * loader other than the {@link ClassLoader#getPlatformClassLoader() + * platform class loader}, or the function to map a module name to a class + * loader returns {@code null}.

+ * *

If the function to map a module name to class loader throws an error * or runtime exception then it is propagated to the caller of this method. *

@@ -565,7 +570,7 @@ public final class Layer { * @apiNote It is implementation specific as to whether creating a Layer * with this method is an atomic operation or not. Consequentially it is * possible for this method to fail with some modules, but not all, defined - * to Java virtual machine. + * to the Java virtual machine. * * @param cf * The configuration for the layer @@ -580,14 +585,7 @@ public final class Layer { * If the parent configurations do not match the configuration of * the parent layers, including order * @throws LayerInstantiationException - * If creating the {@code Layer} fails for any of the reasons - * listed above, the layer cannot be created because the - * configuration contains a module named "{@code java.base}", - * a module with a package name starting with "{@code java.}" is - * mapped to a class loader other than the {@link - * ClassLoader#getPlatformClassLoader() platform class loader}, - * or the function to map a module name to a class loader returns - * {@code null} + * If creating the layer fails for any of the reasons listed above * @throws SecurityException * If {@code RuntimePermission("getClassLoader")} is denied by * the security manager @@ -763,7 +761,7 @@ public final class Layer { /** * Returns the module with the given name in this layer, or if not in this - * layer, the {@linkplain #parents parents} layers. Finding a module in + * layer, the {@linkplain #parents parent} layers. Finding a module in * parent layers is equivalent to invoking {@code findModule} on each * parent, in search order, until the module is found or all parents have * been searched. In a tree of layers then this is equivalent to diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java b/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java index ff61c41590f..fbd0de0ac85 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java @@ -31,6 +31,7 @@ package java.lang.reflect; * @see Layer * * @since 9 + * @spec JPMS */ public class LayerInstantiationException extends RuntimeException { private static final long serialVersionUID = -906239691613568347L; diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java index 027a711d3e1..2208a5cbd81 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Method.java @@ -179,6 +179,10 @@ public final class Method extends Executable { return res; } + /** + * @throws InaccessibleObjectException {@inheritDoc} + * @throws SecurityException {@inheritDoc} + */ @Override @CallerSensitive public void setAccessible(boolean flag) { diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java index 5134b64caf8..e70d9fbb872 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ import java.net.URI; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -74,16 +73,15 @@ import sun.security.util.SecurityConstants; * Java Virtual Machine when a graph of modules is defined to the Java virtual * machine to create a module {@link Layer Layer}.

* - *

An unnamed module does not have a name. There is an unnamed module - * per {@link ClassLoader ClassLoader} that is obtained by invoking the class - * loader's {@link ClassLoader#getUnnamedModule() getUnnamedModule} method. The - * {@link Class#getModule() getModule} method of all types defined by a class - * loader that are not in a named module return the class loader's unnamed + *

An unnamed module does not have a name. There is an unnamed module for + * each {@link ClassLoader ClassLoader}, obtained by invoking its {@link + * ClassLoader#getUnnamedModule() getUnnamedModule} method. All types that are + * not in a named module are members of their defining class loader's unnamed * module.

* *

The package names that are parameters or returned by methods defined in * this class are the fully-qualified names of the packages as defined in - * section 6.5.3 of The Java™ Language Specification , for + * section 6.5.3 of The Java™ Language Specification, for * example, {@code "java.lang"}.

* *

Unless otherwise specified, passing a {@code null} argument to a method @@ -91,6 +89,7 @@ import sun.security.util.SecurityConstants; * be thrown.

* * @since 9 + * @spec JPMS * @see java.lang.Class#getModule */ @@ -327,8 +326,9 @@ public final class Module implements AnnotatedElement { * * @return this module * - * @throws IllegalStateException - * If this is a named module and the caller is not this module + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module * * @see #canRead */ @@ -338,7 +338,7 @@ public final class Module implements AnnotatedElement { if (this.isNamed()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { - throw new IllegalStateException(caller + " != " + this); + throw new IllegalCallerException(caller + " != " + this); } implAddReads(other, true); } @@ -533,8 +533,8 @@ public final class Module implements AnnotatedElement { if (other == this && containsPackage(pn)) return true; - // all packages in open modules are open - if (descriptor.isOpen()) + // all packages in open and automatic modules are open + if (descriptor.isOpen() || descriptor.isAutomatic()) return containsPackage(pn); // exported/opened via module declaration/descriptor @@ -634,8 +634,7 @@ public final class Module implements AnnotatedElement { * the given package to the given module. * *

This method has no effect if the package is already exported (or - * open) to the given module. It also has no effect if - * invoked on an {@link ModuleDescriptor#isOpen open} module.

+ * open) to the given module.

* * @apiNote As specified in section 5.4.3 of the The Java™ * Virtual Machine Specification , if an attempt to resolve a @@ -653,8 +652,9 @@ public final class Module implements AnnotatedElement { * @throws IllegalArgumentException * If {@code pn} is {@code null}, or this is a named module and the * package {@code pn} is not a package in this module - * @throws IllegalStateException - * If this is a named module and the caller is not this module + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module * * @jvms 5.4.3 Resolution * @see #isExported(String,Module) @@ -665,10 +665,10 @@ public final class Module implements AnnotatedElement { throw new IllegalArgumentException("package is null"); Objects.requireNonNull(other); - if (isNamed() && !descriptor.isOpen()) { + if (isNamed()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { - throw new IllegalStateException(caller + " != " + this); + throw new IllegalCallerException(caller + " != " + this); } implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true); } @@ -686,8 +686,7 @@ public final class Module implements AnnotatedElement { * access control checks. * *

This method has no effect if the package is already open - * to the given module. It also has no effect if invoked on an {@link - * ModuleDescriptor#isOpen open} module.

+ * to the given module.

* * @param pn * The package name @@ -699,9 +698,9 @@ public final class Module implements AnnotatedElement { * @throws IllegalArgumentException * If {@code pn} is {@code null}, or this is a named module and the * package {@code pn} is not a package in this module - * @throws IllegalStateException + * @throws IllegalCallerException * If this is a named module and this module has not opened the - * package to at least the caller + * package to at least the caller's module * * @see #isOpen(String,Module) * @see AccessibleObject#setAccessible(boolean) @@ -713,10 +712,10 @@ public final class Module implements AnnotatedElement { throw new IllegalArgumentException("package is null"); Objects.requireNonNull(other); - if (isNamed() && !descriptor.isOpen()) { + if (isNamed()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this && !isOpen(pn, caller)) - throw new IllegalStateException(pn + " is not open to " + caller); + throw new IllegalCallerException(pn + " is not open to " + caller); implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true); } @@ -767,8 +766,8 @@ public final class Module implements AnnotatedElement { Objects.requireNonNull(other); Objects.requireNonNull(pn); - // all packages are open in unnamed and open modules - if (!isNamed() || descriptor.isOpen()) + // all packages are open in unnamed, open, and automatic modules + if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic()) return; // nothing to do if already exported/open to other @@ -819,17 +818,17 @@ public final class Module implements AnnotatedElement { * passed a reference to the service type by other code. This method is * a no-op when invoked on an unnamed module or an automatic module. * - *

This method does not cause {@link - * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be - * re-run.

+ *

This method does not cause {@link Configuration#resolveAndBind + * resolveAndBind} to be re-run.

* * @param service * The service type * * @return this module * - * @throws IllegalStateException - * If this is a named module and the caller is not this module + * @throws IllegalCallerException + * If this is a named module and the caller's module is not this + * module * * @see #canUse(Class) * @see ModuleDescriptor#uses() @@ -841,7 +840,7 @@ public final class Module implements AnnotatedElement { if (isNamed() && !descriptor.isAutomatic()) { Module caller = Reflection.getCallerClass().getModule(); if (caller != this) { - throw new IllegalStateException(caller + " != " + this); + throw new IllegalCallerException(caller + " != " + this); } implAddUses(service); } @@ -894,14 +893,13 @@ public final class Module implements AnnotatedElement { // -- packages -- // Additional packages that are added to the module at run-time. - // The field is volatile as it may be replaced at run-time - private volatile Set extraPackages; + private volatile Map extraPackages; private boolean containsPackage(String pn) { if (descriptor.packages().contains(pn)) return true; - Set extraPackages = this.extraPackages; - if (extraPackages != null && extraPackages.contains(pn)) + Map extraPackages = this.extraPackages; + if (extraPackages != null && extraPackages.containsKey(pn)) return true; return false; } @@ -915,7 +913,7 @@ public final class Module implements AnnotatedElement { * added to the module, dynamic modules * for example, after it was loaded. * - *

For unnamed modules, this method is the equivalent of invoking the + *

For unnamed modules, this method is the equivalent to invoking the * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of * this module's class loader and returning the array of package names.

* @@ -930,12 +928,12 @@ public final class Module implements AnnotatedElement { if (isNamed()) { Set packages = descriptor.packages(); - Set extraPackages = this.extraPackages; + Map extraPackages = this.extraPackages; if (extraPackages == null) { return packages.toArray(new String[0]); } else { return Stream.concat(packages.stream(), - extraPackages.stream()) + extraPackages.keySet().stream()) .toArray(String[]::new); } @@ -955,10 +953,6 @@ public final class Module implements AnnotatedElement { * Add a package to this module. * * @apiNote This method is for Proxy use. - * - * @apiNote This is an expensive operation, not expected to be used often. - * At this time then it does not validate that the package name is a - * valid java identifier. */ void addPackage(String pn) { implAddPackage(pn, true); @@ -976,49 +970,52 @@ public final class Module implements AnnotatedElement { /** * Add a package to this module. * - * If {@code syncVM} is {@code true} then the VM is notified. + * If {@code syncVM} is {@code true} then the VM is notified. This method is + * a no-op if this is an unnamed module or the module already contains the + * package. + * + * @throws IllegalArgumentException if the package name is not legal + * @throws IllegalStateException if the package is defined to another module */ private void implAddPackage(String pn, boolean syncVM) { + // no-op if unnamed module if (!isNamed()) - throw new InternalError("adding package to unnamed module?"); - if (descriptor.isOpen()) - throw new InternalError("adding package to open module?"); + return; + + // no-op if module contains the package + if (containsPackage(pn)) + return; + + // check package name is legal for named modules if (pn.isEmpty()) - throw new InternalError("adding package to module?"); - - if (descriptor.packages().contains(pn)) { - // already in module - return; - } - - Set extraPackages = this.extraPackages; - if (extraPackages != null && extraPackages.contains(pn)) { - // already added - return; - } - synchronized (this) { - // recheck under lock - extraPackages = this.extraPackages; - if (extraPackages != null) { - if (extraPackages.contains(pn)) { - // already added - return; - } - - // copy the set - extraPackages = new HashSet<>(extraPackages); - extraPackages.add(pn); - } else { - extraPackages = Collections.singleton(pn); + throw new IllegalArgumentException("Cannot add package"); + for (int i=0; i extraPackages = this.extraPackages; + if (extraPackages == null) { + synchronized (this) { + extraPackages = this.extraPackages; + if (extraPackages == null) + this.extraPackages = extraPackages = new ConcurrentHashMap<>(); + } + } + + // update VM first in case it fails. This is a no-op if another thread + // beats us to add the package first + if (syncVM) { + // throws IllegalStateException if defined to another module + addPackage0(this, pn); + if (descriptor.isOpen() || descriptor.isAutomatic()) { + addExportsToAll0(this, pn); + } + } + extraPackages.putIfAbsent(pn, Boolean.TRUE); } @@ -1169,8 +1166,9 @@ public final class Module implements AnnotatedElement { Map nameToModule, Module m) { - // The VM doesn't know about open modules so need to export all packages - if (descriptor.isOpen()) { + // The VM doesn't special case open or automatic modules so need to + // export all packages + if (descriptor.isOpen() || descriptor.isAutomatic()) { assert descriptor.opens().isEmpty(); for (String source : descriptor.packages()) { addExportsToAll0(m, source); @@ -1375,35 +1373,44 @@ public final class Module implements AnnotatedElement { /** - * Returns an input stream for reading a resource in this module. The - * {@code name} parameter is a {@code '/'}-separated path name that - * identifies the resource. + * Returns an input stream for reading a resource in this module. + * The {@code name} parameter is a {@code '/'}-separated path name that + * identifies the resource. As with {@link Class#getResourceAsStream + * Class.getResourceAsStream}, this method delegates to the module's class + * loader {@link ClassLoader#findResource(String,String) + * findResource(String,String)} method, invoking it with the module name + * (or {@code null} when the module is unnamed) and the name of the + * resource. If the resource name has a leading slash then it is dropped + * before delegation. * - *

A resource in a named modules may be encapsulated so that + *

A resource in a named module may be encapsulated so that * it cannot be located by code in other modules. Whether a resource can be - * located or not is determined as follows: + * located or not is determined as follows:

* *
    - *
  • The package name of the resource is derived from the - * subsequence of characters that precedes the last {@code '/'} and then - * replacing each {@code '/'} character in the subsequence with - * {@code '.'}. For example, the package name derived for a resource - * named "{@code a/b/c/foo.properties}" is "{@code a.b.c}".
  • + *
  • If the resource name ends with "{@code .class}" then it is not + * encapsulated.
  • * - *
  • If the package name is a package in the module then the package - * must be {@link #isOpen open} the module of the caller of this method. - * If the package is not in the module then the resource is not - * encapsulated. Resources in the unnamed package or "{@code META-INF}", - * for example, are never encapsulated because they can never be - * packages in a named module.
  • - * - *
  • As a special case, resources ending with "{@code .class}" are - * never encapsulated.
  • + *
  • A package name is derived from the resource name. If + * the package name is a {@link #getPackages() package} in the module + * then the resource can only be located by the caller of this method + * when the package is {@link #isOpen(String,Module) open} to at least + * the caller's module. If the resource is not in a package in the module + * then the resource is not encapsulated.
  • *
* + *

In the above, the package name for a resource is derived + * from the subsequence of characters that precedes the last {@code '/'} in + * the name and then replacing each {@code '/'} character in the subsequence + * with {@code '.'}. A leading slash is ignored when deriving the package + * name. As an example, the package name derived for a resource named + * "{@code a/b/c/foo.properties}" is "{@code a.b.c}". A resource name + * with the name "{@code META-INF/MANIFEST.MF}" is never encapsulated + * because "{@code META-INF}" is not a legal package name.

+ * *

This method returns {@code null} if the resource is not in this * module, the resource is encapsulated and cannot be located by the caller, - * or access to the resource is denied by the security manager. + * or access to the resource is denied by the security manager.

* * @param name * The resource name @@ -1413,11 +1420,13 @@ public final class Module implements AnnotatedElement { * @throws IOException * If an I/O error occurs * - * @see java.lang.module.ModuleReader#open(String) + * @see Class#getResourceAsStream(String) */ @CallerSensitive public InputStream getResourceAsStream(String name) throws IOException { - Objects.requireNonNull(name); + if (name.startsWith("/")) { + name = name.substring(1); + } if (isNamed() && !ResourceHelper.isSimpleResource(name)) { Module caller = Reflection.getCallerClass().getModule(); diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java index 15d41a4101d..685aebff39a 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java @@ -25,6 +25,7 @@ package java.lang.reflect; +import java.lang.module.ModuleDescriptor; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; @@ -52,6 +53,9 @@ import sun.reflect.misc.ReflectUtil; import sun.security.action.GetPropertyAction; import sun.security.util.SecurityConstants; +import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC; + + /** * * {@code Proxy} provides static methods for creating objects that act like instances @@ -164,7 +168,8 @@ import sun.security.util.SecurityConstants; * methods is specified as follows: * *
    - *
  1. If all the proxy interfaces are in exported packages: + *
  2. If all the proxy interfaces are in exported or open + * packages: *
      *
    1. if all the proxy interfaces are public, then the proxy class is * public in a package exported by the @@ -178,10 +183,11 @@ import sun.security.util.SecurityConstants; * not possible.
    2. *
    *
  3. - *
  4. If at least one proxy interface is a non-exported package: + *
  5. If at least one proxy interface is in a package that is + * non-exported and non-open: *
      *
    1. if all the proxy interfaces are public, then the proxy class is - * public in a non-exported package of + * public in a non-exported, non-open package of * dynamic module. * The names of the package and the module are unspecified.
    2. * @@ -195,21 +201,22 @@ import sun.security.util.SecurityConstants; *
    * *

    - * Note that if proxy interfaces with a mix of accessibilities -- - * exported public, exported non-public, non-exported public, non-exported non-public -- - * are proxied by the same instance, then the proxy class's accessibility is + * Note that if proxy interfaces with a mix of accessibilities -- for example, + * an exported public interface and a non-exported non-public interface -- are + * proxied by the same instance, then the proxy class's accessibility is * governed by the least accessible proxy interface. *

    * Note that it is possible for arbitrary code to obtain access to a proxy class - * in an exported package with {@link AccessibleObject#setAccessible setAccessible}, - * whereas a proxy class in a non-exported package is never accessible to + * in an open package with {@link AccessibleObject#setAccessible setAccessible}, + * whereas a proxy class in a non-open package is never accessible to * code outside the module of the proxy class. * *

    - * Throughout this specification, a "non-exported package" refers to a package that - * is not exported to all modules. Specifically, it refers to a package that - * either is not exported at all by its containing module or is exported in a - * qualified fashion by its containing module. + * Throughout this specification, a "non-exported package" refers to a package + * that is not exported to all modules, and a "non-open package" refers to + * a package that is not open to all modules. Specifically, these terms refer to + * a package that either is not exported/open by its containing module or is + * exported/open in a qualified fashion by its containing module. * *

    Dynamic Modules

    *

    @@ -272,6 +279,8 @@ import sun.security.util.SecurityConstants; * @author Peter Jones * @see InvocationHandler * @since 1.3 + * @revised 9 + * @spec JPMS */ public class Proxy implements java.io.Serializable { private static final long serialVersionUID = -2222568056686623797L; @@ -358,6 +367,8 @@ public class Proxy implements java.io.Serializable { * to create a proxy instance instead. * * @see Package and Module Membership of Proxy Class + * @revised 9 + * @spec JPMS */ @Deprecated @CallerSensitive @@ -855,7 +866,11 @@ public class Proxy implements java.io.Serializable { // create a dynamic module and setup module access String mn = "jdk.proxy" + counter.incrementAndGet(); String pn = PROXY_PACKAGE_PREFIX + "." + mn; - Module m = Modules.defineModule(ld, mn, Collections.singleton(pn)); + ModuleDescriptor descriptor = + ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC)) + .packages(Set.of(pn)) + .build(); + Module m = Modules.defineModule(ld, descriptor, null); Modules.addReads(m, Proxy.class.getModule()); // java.base to create proxy instance Modules.addExports(m, pn, Object.class.getModule()); @@ -955,6 +970,8 @@ public class Proxy implements java.io.Serializable { * {@code null} * * @see Package and Module Membership of Proxy Class + * @revised 9 + * @spec JPMS */ @CallerSensitive public static Object newProxyInstance(ClassLoader loader, @@ -1039,6 +1056,9 @@ public class Proxy implements java.io.Serializable { * @return {@code true} if the class is a proxy class and * {@code false} otherwise * @throws NullPointerException if {@code cl} is {@code null} + * + * @revised 9 + * @spec JPMS */ public static boolean isProxyClass(Class cl) { return Proxy.class.isAssignableFrom(cl) && ProxyBuilder.isProxyClass(cl); diff --git a/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java b/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java index c8cb0257b2a..97800b1ce13 100644 --- a/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java +++ b/jdk/src/java.base/share/classes/java/lang/reflect/package-info.java @@ -45,5 +45,7 @@ * members declared by a given class. * * @since 1.1 + * @revised 9 + * @spec JPMS */ package java.lang.reflect; diff --git a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java index 2e52fe2b4e9..d6bd9546750 100644 --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java @@ -228,6 +228,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * allow creation of a class loader. * * @since 9 + * @spec JPMS */ public URLClassLoader(String name, URL[] urls, @@ -262,6 +263,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * creation of a class loader. * * @since 9 + * @spec JPMS */ public URLClassLoader(String name, URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) { @@ -558,6 +560,9 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { * @throws IllegalArgumentException if the package name is * already defined by this class loader * @return the newly defined {@code Package} object + * + * @revised 9 + * @spec JPMS */ protected Package definePackage(String name, Manifest man, URL url) { String path = name.replace('.', '/').concat("/"); diff --git a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java index 8f84e10324e..4f0bfa4c27f 100644 --- a/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java +++ b/jdk/src/java.base/share/classes/java/security/SecureClassLoader.java @@ -125,6 +125,7 @@ public class SecureClassLoader extends ClassLoader { * doesn't allow creation of a class loader. * * @since 9 + * @spec JPMS */ protected SecureClassLoader(String name, ClassLoader parent) { super(name, parent); diff --git a/jdk/src/java.base/share/classes/java/security/Security.java b/jdk/src/java.base/share/classes/java/security/Security.java index 49b7e991b40..1076b1d7da7 100644 --- a/jdk/src/java.base/share/classes/java/security/Security.java +++ b/jdk/src/java.base/share/classes/java/security/Security.java @@ -25,11 +25,12 @@ package java.security; -import java.lang.reflect.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.io.*; import java.net.URL; + +import jdk.internal.misc.SharedSecrets; import sun.security.util.Debug; import sun.security.util.PropertyExpander; @@ -800,9 +801,6 @@ public final class Security { * "package.definition", we need to signal to the SecurityManager * class that the value has just changed, and that it should * invalidate it's local cache values. - * - * Rather than create a new API entry for this function, - * we use reflection to set a private variable. */ private static void invalidateSMCache(String key) { @@ -810,42 +808,8 @@ public final class Security { final boolean pd = key.equals("package.definition"); if (pa || pd) { - AccessController.doPrivileged(new PrivilegedAction<>() { - public Void run() { - try { - /* Get the class via the bootstrap class loader. */ - Class cl = Class.forName( - "java.lang.SecurityManager", false, null); - Field f = null; - boolean accessible = false; - - if (pa) { - f = cl.getDeclaredField("packageAccessValid"); - accessible = f.isAccessible(); - f.setAccessible(true); - } else { - f = cl.getDeclaredField("packageDefinitionValid"); - accessible = f.isAccessible(); - f.setAccessible(true); - } - f.setBoolean(f, false); - f.setAccessible(accessible); - } - catch (Exception e1) { - /* If we couldn't get the class, it hasn't - * been loaded yet. If there is no such - * field, we shouldn't try to set it. There - * shouldn't be a security execption, as we - * are loaded by boot class loader, and we - * are inside a doPrivileged() here. - * - * NOOP: don't do anything... - */ - } - return null; - } /* run */ - }); /* PrivilegedAction */ - } /* if */ + SharedSecrets.getJavaLangAccess().invalidatePackageAccessCache(); + } } private static void check(String directive) { diff --git a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java index 600b1810a2e..b587da9b9e3 100644 --- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java @@ -350,6 +350,8 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; * @see MissingResourceException * @see ResourceBundleProvider * @since 1.1 + * @revised 9 + * @spec JPMS */ public abstract class ResourceBundle { @@ -870,6 +872,8 @@ public abstract class ResourceBundle { * @throws UnsupportedOperationException * if this method is called in a named module * @since 1.6 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, @@ -938,6 +942,7 @@ public abstract class ResourceBundle { * specified module * @return a resource bundle for the given base name and the default locale * @since 9 + * @spec JPMS * @see ResourceBundleProvider */ @CallerSensitive @@ -991,6 +996,7 @@ public abstract class ResourceBundle { * be found in the specified {@code module} * @return a resource bundle for the given base name and locale in the module * @since 9 + * @spec JPMS */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) { @@ -1036,6 +1042,8 @@ public abstract class ResourceBundle { * @throws UnsupportedOperationException * if this method is called in a named module * @since 1.6 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale targetLocale, @@ -1243,6 +1251,8 @@ public abstract class ResourceBundle { * @exception MissingResourceException * if no resource bundle for the specified base name can be found * @since 1.2 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale locale, @@ -1465,6 +1475,8 @@ public abstract class ResourceBundle { * @throws UnsupportedOperationException * if this method is called in a named module * @since 1.6 + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale targetLocale, @@ -2194,6 +2206,8 @@ public abstract class ResourceBundle { * by the caller's module. * * @since 1.6 + * @revised 9 + * @spec JPMS * @see ResourceBundle.Control#getTimeToLive(String,Locale) */ @CallerSensitive @@ -2475,6 +2489,8 @@ public abstract class ResourceBundle { * of {@link ResourceBundleControlProvider} are ignored in named modules. * * @since 1.6 + * @revised 9 + * @spec JPMS * @see java.util.spi.ResourceBundleProvider */ public static class Control { @@ -3103,6 +3119,8 @@ public abstract class ResourceBundle { * if an error occurred when reading resources using * any I/O operations * @see java.util.spi.ResourceBundleProvider#getBundle(String, Locale) + * @revised 9 + * @spec JPMS */ public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) diff --git a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java index 0b437d44e2e..6ffb6177e39 100644 --- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java @@ -119,7 +119,7 @@ import jdk.internal.reflect.Reflection; * and deployed as an explicit module must have an appropriate uses * clause in its module descriptor to declare that the module uses * implementations of the service. A corresponding requirement is that a - * provider deployed as a named module must have an appropriate + * provider deployed as an explicit module must have an appropriate * provides clause in its module descriptor to declare that the module * provides an implementation of the service. The uses and * provides allow consumers of a service to be linked to modules @@ -203,8 +203,11 @@ import jdk.internal.reflect.Reflection; * ordering of modules in a layer, is not defined.

  6. * *
  7. If a named module declares more than one provider then the providers - * are located in the order that they appear in the {@code provides} table of - * the {@code Module} class file attribute ({@code module-info.class}).
  8. + * are located in the iteration order of the {@link + * java.lang.module.ModuleDescriptor.Provides#providers() providers} list. + * Providers added dynamically by instrumentation agents ({@link + * java.lang.instrument.Instrumentation#redefineModule redefineModule}) + * are always located after providers declared by the module. * *
  9. When locating providers in unnamed modules then the ordering is * based on the order that the class loader's {@link @@ -335,6 +338,8 @@ import jdk.internal.reflect.Reflection; * * @author Mark Reinhold * @since 1.6 + * @revised 9 + * @spec JPMS */ public final class ServiceLoader @@ -386,6 +391,7 @@ public final class ServiceLoader * * @param The service type * @since 9 + * @spec JPMS */ public static interface Provider extends Supplier { /** @@ -927,26 +933,28 @@ public final class ServiceLoader } else { catalog = ServicesCatalog.getServicesCatalogOrNull(loader); } - Stream stream1; + List providers; if (catalog == null) { - stream1 = Stream.empty(); + providers = List.of(); } else { - stream1 = catalog.findServices(serviceName).stream(); + providers = catalog.findServices(serviceName); } // modules in custom layers that define modules to the class loader - Stream stream2; if (loader == null) { - stream2 = Stream.empty(); + return providers.iterator(); } else { + List allProviders = new ArrayList<>(providers); Layer bootLayer = Layer.boot(); - stream2 = JLRM_ACCESS.layers(loader) - .filter(l -> (l != bootLayer)) - .map(l -> providers(l)) - .flatMap(List::stream); + Iterator iterator = JLRM_ACCESS.layers(loader).iterator(); + while (iterator.hasNext()) { + Layer layer = iterator.next(); + if (layer != bootLayer) { + allProviders.addAll(providers(layer)); + } + } + return allProviders.iterator(); } - - return Stream.concat(stream1, stream2).iterator(); } @Override @@ -1214,6 +1222,9 @@ public final class ServiceLoader * * @return An iterator that lazily loads providers for this loader's * service + * + * @revised 9 + * @spec JPMS */ public Iterator iterator() { @@ -1279,8 +1290,10 @@ public final class ServiceLoader * provider to be loaded.

    * *

    If this loader's provider caches are cleared by invoking the {@link - * #reload() reload} method then existing streams for this service - * loader should be discarded.

    + * #reload() reload} method then existing streams for this service loader + * should be discarded. The returned stream's source {@code Spliterator} is + * fail-fast and will throw {@link ConcurrentModificationException} + * if the provider cache has been cleared.

    * *

    The following examples demonstrate usage. The first example * creates a stream of providers, the second example is the same except @@ -1300,6 +1313,7 @@ public final class ServiceLoader * @return A stream that lazily loads providers for this loader's service * * @since 9 + * @spec JPMS */ public Stream> stream() { // use cached providers as the source when all providers loaded @@ -1414,6 +1428,9 @@ public final class ServiceLoader * if the service type is not accessible to the caller or the * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} + * + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader load(Class service, @@ -1457,6 +1474,9 @@ public final class ServiceLoader * if the service type is not accessible to the caller or the * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} + * + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader load(Class service) { @@ -1490,6 +1510,9 @@ public final class ServiceLoader * if the service type is not accessible to the caller or the * caller is in an explicit module and its module descriptor does * not declare that it uses {@code service} + * + * @revised 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader loadInstalled(Class service) { @@ -1522,6 +1545,7 @@ public final class ServiceLoader * not declare that it uses {@code service} * * @since 9 + * @spec JPMS */ @CallerSensitive public static ServiceLoader load(Layer layer, Class service) { @@ -1551,6 +1575,7 @@ public final class ServiceLoader * or error is thrown when locating or instantiating the provider. * * @since 9 + * @spec JPMS */ public Optional findFirst() { Iterator iterator = iterator(); diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index c549dbdb30f..330f4fb78a3 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -40,6 +40,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.security.AccessController; import java.security.AccessControlContext; +import java.security.Permission; import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; @@ -132,24 +133,30 @@ import java.util.concurrent.locks.LockSupport; * * * - *

    The common pool is by default constructed with default - * parameters, but these may be controlled by setting the following - * {@linkplain System#getProperty system properties}: + *

    The parameters used to construct the common pool may be controlled by + * setting the following {@linkplain System#getProperty system properties}: *

      *
    • {@code java.util.concurrent.ForkJoinPool.common.parallelism} * - the parallelism level, a non-negative integer *
    • {@code java.util.concurrent.ForkJoinPool.common.threadFactory} - * - the class name of a {@link ForkJoinWorkerThreadFactory} + * - the class name of a {@link ForkJoinWorkerThreadFactory}. + * The {@linkplain ClassLoader#getSystemClassLoader() system class loader} + * is used to load this class. *
    • {@code java.util.concurrent.ForkJoinPool.common.exceptionHandler} - * - the class name of a {@link UncaughtExceptionHandler} + * - the class name of a {@link UncaughtExceptionHandler}. + * The {@linkplain ClassLoader#getSystemClassLoader() system class loader} + * is used to load this class. *
    • {@code java.util.concurrent.ForkJoinPool.common.maximumSpares} * - the maximum number of allowed extra threads to maintain target * parallelism (default 256). *
    - * If a {@link SecurityManager} is present and no factory is - * specified, then the default pool uses a factory supplying - * threads that have no {@link Permissions} enabled. - * The system class loader is used to load these classes. + * If no thread factory is supplied via a system property, then the + * common pool uses a factory that uses the system class loader as the + * {@linkplain Thread#getContextClassLoader() thread context class loader}. + * In addition, if a {@link SecurityManager} is present, then + * the common pool uses a factory supplying threads that have no + * {@link Permissions} enabled. + * * Upon any error in establishing these settings, default parameters * are used. It is possible to disable or limit the use of threads in * the common pool by setting the parallelism property to zero, and/or @@ -638,20 +645,38 @@ public class ForkJoinPool extends AbstractExecutorService { * * @param pool the pool this thread works in * @return the new worker thread, or {@code null} if the request - * to create a thread is rejected. + * to create a thread is rejected * @throws NullPointerException if the pool is null */ public ForkJoinWorkerThread newThread(ForkJoinPool pool); } + static AccessControlContext contextWithPermissions(Permission ... perms) { + Permissions permissions = new Permissions(); + for (Permission perm : perms) + permissions.add(perm); + return new AccessControlContext( + new ProtectionDomain[] { new ProtectionDomain(null, permissions) }); + } + /** * Default ForkJoinWorkerThreadFactory implementation; creates a - * new ForkJoinWorkerThread. + * new ForkJoinWorkerThread using the system class loader as the + * thread context class loader. */ private static final class DefaultForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory { + private static final AccessControlContext ACC = contextWithPermissions( + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader")); + public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { - return new ForkJoinWorkerThread(pool); + return AccessController.doPrivileged( + new PrivilegedAction<>() { + public ForkJoinWorkerThread run() { + return new ForkJoinWorkerThread( + pool, ClassLoader.getSystemClassLoader()); }}, + ACC); } } @@ -3244,26 +3269,20 @@ public class ForkJoinPool extends AbstractExecutorService { * An ACC to restrict permissions for the factory itself. * The constructed workers have no permissions set. */ - private static final AccessControlContext INNOCUOUS_ACC; - static { - Permissions innocuousPerms = new Permissions(); - innocuousPerms.add(modifyThreadPermission); - innocuousPerms.add(new RuntimePermission( - "enableContextClassLoaderOverride")); - innocuousPerms.add(new RuntimePermission( - "modifyThreadGroup")); - INNOCUOUS_ACC = new AccessControlContext(new ProtectionDomain[] { - new ProtectionDomain(null, innocuousPerms) - }); - } + private static final AccessControlContext ACC = contextWithPermissions( + modifyThreadPermission, + new RuntimePermission("enableContextClassLoaderOverride"), + new RuntimePermission("modifyThreadGroup"), + new RuntimePermission("getClassLoader"), + new RuntimePermission("setContextClassLoader")); public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { - return AccessController.doPrivileged(new PrivilegedAction<>() { - public ForkJoinWorkerThread run() { - return new ForkJoinWorkerThread. - InnocuousForkJoinWorkerThread(pool); - }}, INNOCUOUS_ACC); + return AccessController.doPrivileged( + new PrivilegedAction<>() { + public ForkJoinWorkerThread run() { + return new ForkJoinWorkerThread. + InnocuousForkJoinWorkerThread(pool); }}, + ACC); } } - } diff --git a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java index 93bb08dd48f..a3054b865ba 100644 --- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java +++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java @@ -36,6 +36,8 @@ package java.util.concurrent; import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.security.ProtectionDomain; /** @@ -87,12 +89,27 @@ public class ForkJoinWorkerThread extends Thread { this.workQueue = pool.registerWorker(this); } + /** + * Version for use by the default pool. Supports setting the + * context class loader. This is a separate constructor to avoid + * affecting the protected constructor. + */ + ForkJoinWorkerThread(ForkJoinPool pool, ClassLoader ccl) { + super("aForkJoinWorkerThread"); + super.setContextClassLoader(ccl); + this.pool = pool; + this.workQueue = pool.registerWorker(this); + } + /** * Version for InnocuousForkJoinWorkerThread. */ - ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup, + ForkJoinWorkerThread(ForkJoinPool pool, + ClassLoader ccl, + ThreadGroup threadGroup, AccessControlContext acc) { super(threadGroup, null, "aForkJoinWorkerThread"); + super.setContextClassLoader(ccl); ThreadLocalRandom.setInheritedAccessControlContext(this, acc); ThreadLocalRandom.eraseThreadLocals(this); // clear before registering this.pool = pool; @@ -179,20 +196,21 @@ public class ForkJoinWorkerThread extends Thread { /** * A worker thread that has no permissions, is not a member of any - * user-defined ThreadGroup, and erases all ThreadLocals after + * user-defined ThreadGroup, uses the system class loader as + * thread context class loader, and erases all ThreadLocals after * running each top-level task. */ static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread { /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */ private static final ThreadGroup innocuousThreadGroup = - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction<>() { - public ThreadGroup run() { - ThreadGroup group = Thread.currentThread().getThreadGroup(); - for (ThreadGroup p; (p = group.getParent()) != null; ) - group = p; - return new ThreadGroup(group, "InnocuousForkJoinWorkerThreadGroup"); - }}); + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction<>() { + public ThreadGroup run() { + ThreadGroup group = Thread.currentThread().getThreadGroup(); + for (ThreadGroup p; (p = group.getParent()) != null; ) + group = p; + return new ThreadGroup(group, "InnocuousForkJoinWorkerThreadGroup"); + }}); /** An AccessControlContext supporting no privileges */ private static final AccessControlContext INNOCUOUS_ACC = @@ -202,7 +220,10 @@ public class ForkJoinWorkerThread extends Thread { }); InnocuousForkJoinWorkerThread(ForkJoinPool pool) { - super(pool, innocuousThreadGroup, INNOCUOUS_ACC); + super(pool, + ClassLoader.getSystemClassLoader(), + innocuousThreadGroup, + INNOCUOUS_ACC); } @Override // to erase ThreadLocals @@ -210,11 +231,6 @@ public class ForkJoinWorkerThread extends Thread { ThreadLocalRandom.eraseThreadLocals(this); } - @Override // to always report system loader - public ClassLoader getContextClassLoader() { - return ClassLoader.getSystemClassLoader(); - } - @Override // to silently fail public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { } diff --git a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java index 06b6c266c89..b0cba4f4915 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java @@ -81,6 +81,7 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; * ResourceBundleProvider Service Providers * * @since 9 + * @spec JPMS */ public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider { private static final JavaUtilResourceBundleAccess RB_ACCESS = diff --git a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java index f74830b4d6a..871d9192ec0 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java @@ -44,6 +44,8 @@ import java.util.ResourceBundle; * * @author Masayoshi Okutsu * @since 1.8 + * @revised 9 + * @spec JPMS * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control) * ResourceBundle.getBundle * @see java.util.ServiceLoader#load(Class) diff --git a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java index 0074ae32090..251831f1dcb 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java @@ -57,6 +57,7 @@ import java.util.ResourceBundle; * @see * ResourceBundleProvider Service Providers * @since 9 + * @spec JPMS */ public interface ResourceBundleProvider { /** diff --git a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java index 34e99dfdd9b..289a80fdca6 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java @@ -186,7 +186,7 @@ public class JmodFile implements AutoCloseable { public Entry getEntry(Section section, String name) { String entry = section.jmodDir() + "/" + name; ZipEntry ze = zipfile.getEntry(entry); - return (ze != null) ? new Entry(ze) : null; + return (ze == null || ze.isDirectory()) ? null : new Entry(ze); } /** @@ -201,7 +201,7 @@ public class JmodFile implements AutoCloseable { { String entry = section.jmodDir() + "/" + name; ZipEntry e = zipfile.getEntry(entry); - if (e == null) { + if (e == null || e.isDirectory()) { throw new IOException(name + " not found: " + file); } return zipfile.getInputStream(e); diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java index ab052ec0b30..a0886e82080 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java @@ -57,8 +57,9 @@ import java.util.jar.Attributes; import java.util.jar.Manifest; import java.util.stream.Stream; -import jdk.internal.module.ModulePatcher.PatchedModuleReader; import jdk.internal.misc.VM; +import jdk.internal.module.ModulePatcher.PatchedModuleReader; +import jdk.internal.module.SystemModules; /** @@ -135,7 +136,7 @@ public class BuiltinClassLoader // maps package name to loaded module for modules in the boot layer private static final Map packageToModule - = new ConcurrentHashMap<>(1024); + = new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER); // maps a module name to a module reference private final Map nameToModule; @@ -922,13 +923,13 @@ public class BuiltinClassLoader * Returns the ModuleReader for the given module. */ private ModuleReader moduleReaderFor(ModuleReference mref) { - return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref)); + return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader); } /** * Creates a ModuleReader for the given module. */ - private ModuleReader createModuleReader(ModuleReference mref) { + private static ModuleReader createModuleReader(ModuleReference mref) { try { return mref.open(); } catch (IOException e) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java index a9e0750391a..18a42b7b6f3 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,10 @@ */ package jdk.internal.loader; +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + import jdk.internal.module.Checks; /** @@ -34,7 +38,8 @@ public final class ResourceHelper { private ResourceHelper() { } /** - * Returns the package name for a resource. + * Returns the package name for a resource or the empty package if + * the resource name does not contain a slash. */ public static String getPackageName(String name) { int index = name.lastIndexOf('/'); @@ -46,19 +51,75 @@ public final class ResourceHelper { } /** - * Returns true if the resource is a simple resource that can - * never be encapsulated. Resources ending in "{@code .class}" or where - * the package name is not a Java identifier are resources that can - * never be encapsulated. + * Returns true if the resource is a simple resource. Simple + * resources can never be encapsulated. Resources ending in "{@code .class}" + * or where the package name is not a legal package name can not be + * encapsulated. */ public static boolean isSimpleResource(String name) { int len = name.length(); if (len > 6 && name.endsWith(".class")) { return true; } - if (!Checks.isJavaIdentifier(getPackageName(name))) { + if (!Checks.isPackageName(getPackageName(name))) { return true; } return false; } + + /** + * Converts a resource name to a file path. Returns {@code null} if the + * resource name cannot be converted into a file path. Resource names + * with empty elements, or elements that are "." or ".." are rejected, + * as is a resource name that translates to a file path with a root + * component. + */ + public static Path toFilePath(String name) { + // scan the resource name to eagerly reject obviously invalid names + int next; + int off = 0; + while ((next = name.indexOf('/', off)) != -1) { + int len = next - off; + if (!mayTranslate(name, off, len)) { + return null; + } + off = next + 1; + } + int rem = name.length() - off; + if (!mayTranslate(name, off, rem)) { + return null; + } + + // convert to file path + Path path; + if (File.separatorChar == '/') { + path = Paths.get(name); + } else { + // not allowed to embed file separators + if (name.contains(File.separator)) + return null; + path = Paths.get(name.replace('/', File.separatorChar)); + } + + // file path not allowed to have root component + return (path.getRoot() == null) ? path : null; + } + + /** + * Returns {@code true} if the element in a resource name is a candidate + * to translate to the element of a file path. + */ + private static boolean mayTranslate(String name, int off, int len) { + if (len <= 2) { + if (len == 0) + return false; + boolean starsWithDot = (name.charAt(off) == '.'); + if (len == 1 && starsWithDot) + return false; + if (len == 2 && starsWithDot && (name.charAt(off+1) == '.')) + return false; + } + return true; + } + } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java index 6838111c35d..7cb2c1e74a4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java @@ -174,4 +174,9 @@ public interface JavaLangAccess { * Invokes Long.fastUUID */ String fastUUID(long lsb, long msb); + + /** + * Invalidate package access cache + */ + void invalidatePackageAccessCache(); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java index eed7a2d2aff..53e8b4c82c7 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,20 +59,21 @@ public interface JavaLangModuleAccess { */ ModuleDescriptor.Builder newModuleBuilder(String mn, boolean strict, - boolean open, - boolean synthetic); + Set ms); /** - * Returns the set of packages that are exported (unconditionally or - * unconditionally). + * Returns a snapshot of the packages in the module. */ - Set exportedPackages(ModuleDescriptor.Builder builder); + Set packages(ModuleDescriptor.Builder builder); /** - * Returns the set of packages that are opened (unconditionally or - * unconditionally). + * Adds a dependence on a module with the given (possibly un-parsable) + * version string. */ - Set openPackages(ModuleDescriptor.Builder builder); + void requires(ModuleDescriptor.Builder builder, + Set ms, + String mn, + String compiledVersion); /** * Returns a {@code ModuleDescriptor.Requires} of the given modifiers @@ -113,24 +114,12 @@ public interface JavaLangModuleAccess { */ Provides newProvides(String service, List providers); - /** - * Returns a {@code ModuleDescriptor.Version} of the given version. - */ - Version newVersion(String v); - - /** - * Clones the given module descriptor with an augmented set of packages - */ - ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, Set pkgs); - /** * Returns a new {@code ModuleDescriptor} instance. */ ModuleDescriptor newModuleDescriptor(String name, Version version, - boolean open, - boolean automatic, - boolean synthetic, + Set ms, Set requires, Set exports, Set opens, @@ -148,9 +137,9 @@ public interface JavaLangModuleAccess { * and the empty configuration as the parent. The post resolution * checks are optionally run. */ - Configuration resolveRequiresAndUses(ModuleFinder finder, - Collection roots, - boolean check, - PrintStream traceOutput); + Configuration resolveAndBind(ModuleFinder finder, + Collection roots, + boolean check, + PrintStream traceOutput); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java index 2ef9c11d248..9196f39ff77 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,7 @@ import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; /** - * This builder is optimized for reconstituting ModuleDescriptor + * This builder is optimized for reconstituting the {@code ModuleDescriptor}s * for system modules. The validation should be done at jlink time. * * 1. skip name validation @@ -136,9 +136,7 @@ final class Builder { } final String name; - boolean open; - boolean automatic; - boolean synthetic; + boolean open, synthetic, mandated; Set requires; Set exports; Set opens; @@ -165,13 +163,13 @@ final class Builder { return this; } - Builder automatic(boolean value) { - this.automatic = value; + Builder synthetic(boolean value) { + this.synthetic = value; return this; } - Builder synthetic(boolean value) { - this.synthetic = value; + Builder mandated(boolean value) { + this.mandated = value; return this; } @@ -228,13 +226,10 @@ final class Builder { * * @throws IllegalArgumentException if {@code v} is null or cannot be * parsed as a version string - * @throws IllegalStateException if the module version is already set * * @see Version#parse(String) */ public Builder version(String v) { - if (version != null) - throw new IllegalStateException("module version already set"); Version ver = cachedVersion; if (ver != null && v.equals(ver.toString())) { version = ver; @@ -246,63 +241,63 @@ final class Builder { /** * Sets the module main class. - * - * @throws IllegalStateException if already set */ public Builder mainClass(String mc) { - if (mainClass != null) - throw new IllegalStateException("main class already set"); mainClass = mc; return this; } /** * Sets the OS name. - * - * @throws IllegalStateException if already set */ public Builder osName(String name) { - if (osName != null) - throw new IllegalStateException("OS name already set"); this.osName = name; return this; } /** * Sets the OS arch. - * - * @throws IllegalStateException if already set */ public Builder osArch(String arch) { - if (osArch != null) - throw new IllegalStateException("OS arch already set"); this.osArch = arch; return this; } /** * Sets the OS version. - * - * @throws IllegalStateException if already set */ public Builder osVersion(String version) { - if (osVersion != null) - throw new IllegalStateException("OS version already set"); this.osVersion = version; return this; } + /** + * Returns an immutable set of the module modifiers derived from the flags. + */ + private Set modifiers() { + int n = 0; + if (open) n++; + if (synthetic) n++; + if (mandated) n++; + if (n == 0) { + return Collections.emptySet(); + } else { + ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n]; + if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN; + if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC; + if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED; + return Set.of(mods); + } + } + /** * Builds a {@code ModuleDescriptor} from the components. */ public ModuleDescriptor build(int hashCode) { assert name != null; - return JLMA.newModuleDescriptor(name, version, - open, - automatic, - synthetic, + modifiers(), requires, exports, opens, diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java index 2fdeaab6211..e19e6528ce0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +26,7 @@ package jdk.internal.module; /** - * Utility class for checking module name and binary names. + * Utility class for checking module, package, and class names. */ public final class Checks { @@ -58,8 +58,6 @@ public final class Checks { throw new IllegalArgumentException(name + ": Invalid module name" + ": '" + id + "' is not a Java identifier"); } - //if (!Character.isJavaIdentifierStart(last)) - // throw new IllegalArgumentException(name + ": Module name ends in digit"); return name; } @@ -77,8 +75,6 @@ public final class Checks { int last = isJavaIdentifier(name, off, name.length() - off); if (last == -1) return false; - //if (!Character.isJavaIdentifierStart(last)) - // return false; return true; } @@ -89,40 +85,62 @@ public final class Checks { * package name */ public static String requirePackageName(String name) { - return requireBinaryName("package name", name); + return requireTypeName("package name", name); } /** - * Checks a name to ensure that it's a legal type name. + * Returns {@code true} if the given name is a legal package name. + */ + public static boolean isPackageName(String name) { + return isTypeName(name); + } + + /** + * Checks a name to ensure that it's a legal qualified class name * * @throws IllegalArgumentException if name is null or not a legal - * type name + * qualified class name */ public static String requireServiceTypeName(String name) { - return requireBinaryName("service type name", name); + return requireQualifiedClassName("service type name", name); } /** - * Checks a name to ensure that it's a legal type name. + * Checks a name to ensure that it's a legal qualified class name. * * @throws IllegalArgumentException if name is null or not a legal - * type name + * qualified class name */ public static String requireServiceProviderName(String name) { - return requireBinaryName("service provider name", name); + return requireQualifiedClassName("service provider name", name); } /** - * Returns {@code true} if the given name is a legal binary name. + * Checks a name to ensure that it's a legal qualified class name in + * a named package. + * + * @throws IllegalArgumentException if name is null or not a legal + * qualified class name in a named package */ - public static boolean isJavaIdentifier(String name) { - return isBinaryName(name); + public static String requireQualifiedClassName(String what, String name) { + requireTypeName(what, name); + if (name.indexOf('.') == -1) + throw new IllegalArgumentException(name + ": is not a qualified name of" + + " a Java class in a named package"); + return name; } /** - * Returns {@code true} if the given name is a legal binary name. + * Returns {@code true} if the given name is a legal class name. */ - public static boolean isBinaryName(String name) { + public static boolean isClassName(String name) { + return isTypeName(name); + } + + /** + * Returns {@code true} if the given name is a legal type name. + */ + private static boolean isTypeName(String name) { int next; int off = 0; while ((next = name.indexOf('.', off)) != -1) { @@ -135,12 +153,12 @@ public final class Checks { } /** - * Checks if the given name is a legal binary name. + * Checks if the given name is a legal type name. * * @throws IllegalArgumentException if name is null or not a legal - * binary name + * type name */ - public static String requireBinaryName(String what, String name) { + private static String requireTypeName(String what, String name) { if (name == null) throw new IllegalArgumentException("Null " + what); int next; diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java index 69c7ee670dd..fc3c3904850 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package jdk.internal.module; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Opens; @@ -98,14 +99,17 @@ public final class ClassFileAttributes { // module_flags int module_flags = cr.readUnsignedShort(off); - boolean open = ((module_flags & ACC_OPEN) != 0); - boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0); off += 2; - ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn, - false, - open, - synthetic); + Set modifiers = new HashSet<>(); + if ((module_flags & ACC_OPEN) != 0) + modifiers.add(ModuleDescriptor.Modifier.OPEN); + if ((module_flags & ACC_SYNTHETIC) != 0) + modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC); + if ((module_flags & ACC_MANDATED) != 0) + modifiers.add(ModuleDescriptor.Modifier.MANDATED); + + Builder builder = JLMA.newModuleBuilder(mn, false, modifiers); // module_version String module_version = cr.readUTF8(off, buf); @@ -142,19 +146,13 @@ public final class ClassFileAttributes { mods.add(Requires.Modifier.MANDATED); } - // requires_version - Version compiledVersion = null; String requires_version = cr.readUTF8(off, buf); off += 2; - if (requires_version != null) { - compiledVersion = Version.parse(requires_version); - } - - if (compiledVersion == null) { + if (requires_version == null) { builder.requires(mods, dn); } else { - builder.requires(mods, dn, compiledVersion); + JLMA.requires(builder, mods, dn, requires_version); } } @@ -283,11 +281,14 @@ public final class ClassFileAttributes { attr.putShort(module_name_index); // module_flags + Set modifiers = descriptor.modifiers(); int module_flags = 0; - if (descriptor.isOpen()) + if (modifiers.contains(ModuleDescriptor.Modifier.OPEN)) module_flags |= ACC_OPEN; - if (descriptor.isSynthetic()) + if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC)) module_flags |= ACC_SYNTHETIC; + if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED)) + module_flags |= ACC_MANDATED; attr.putShort(module_flags); // module_version diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java index 48fe536c7aa..66e241ee555 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,8 +46,8 @@ public class ClassFileConstants { // access, requires, exports, and opens flags public static final int ACC_MODULE = 0x8000; public static final int ACC_OPEN = 0x0020; - public static final int ACC_TRANSITIVE = 0x0010; - public static final int ACC_STATIC_PHASE = 0x0020; + public static final int ACC_TRANSITIVE = 0x0020; + public static final int ACC_STATIC_PHASE = 0x0040; public static final int ACC_SYNTHETIC = 0x1000; public static final int ACC_MANDATED = 0x8000; diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 71406460c41..6fe2e7423b7 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; +import java.util.stream.Stream; import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; @@ -114,7 +115,12 @@ public final class ModuleBootstrap { long t0 = System.nanoTime(); // system modules (may be patched) - ModuleFinder systemModules = ModuleFinder.ofSystem(); + ModuleFinder systemModules; + if (SystemModules.MODULE_NAMES.length > 0) { + systemModules = SystemModuleFinder.getInstance(); + } else { + systemModules = ModuleFinder.ofSystem(); + } PerfCounters.systemModulesTime.addElapsedTimeFrom(t0); @@ -275,10 +281,10 @@ public final class ModuleBootstrap { // run the resolver to create the configuration Configuration cf = SharedSecrets.getJavaLangModuleAccess() - .resolveRequiresAndUses(finder, - roots, - needPostResolutionChecks, - traceOutput); + .resolveAndBind(finder, + roots, + needPostResolutionChecks, + traceOutput); // time to create configuration PerfCounters.resolveTime.addElapsedTimeFrom(t3); @@ -318,20 +324,20 @@ public final class ModuleBootstrap { // if needed check that there are no split packages in the set of // resolved modules for the boot layer if (SystemModules.hasSplitPackages() || needPostResolutionChecks) { - Map packageToModule = new HashMap<>(); - for (ResolvedModule resolvedModule : cf.modules()) { - ModuleDescriptor descriptor = - resolvedModule.reference().descriptor(); - String name = descriptor.name(); - for (String p : descriptor.packages()) { - String other = packageToModule.putIfAbsent(p, name); - if (other != null) { - fail("Package " + p + " in both module " - + name + " and module " + other); - } + Map packageToModule = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleDescriptor descriptor = + resolvedModule.reference().descriptor(); + String name = descriptor.name(); + for (String p : descriptor.packages()) { + String other = packageToModule.putIfAbsent(p, name); + if (other != null) { + fail("Package " + p + " in both module " + + name + " and module " + other); } } } + } long t4 = System.nanoTime(); @@ -380,10 +386,9 @@ public final class ModuleBootstrap { Set otherMods) { // resolve all root modules - Configuration cf = Configuration.empty() - .resolveRequires(finder, - ModuleFinder.of(), - roots); + Configuration cf = Configuration.empty().resolve(finder, + ModuleFinder.of(), + roots); // module name -> reference Map map = new HashMap<>(); @@ -416,7 +421,7 @@ public final class ModuleBootstrap { /** * Creates a finder from the module path that is the value of the given - * system property. + * system property and optionally patched by --patch-module */ private static ModuleFinder createModulePathFinder(String prop) { String s = System.getProperty(prop); @@ -429,7 +434,7 @@ public final class ModuleBootstrap { for (String dir: dirs) { paths[i++] = Paths.get(dir); } - return ModuleFinder.of(paths); + return ModulePath.of(patcher, paths); } } @@ -528,6 +533,7 @@ public final class ModuleBootstrap { if (!extraOpens.isEmpty()) { addExtraExportsOrOpens(bootLayer, extraOpens, true); } + } private static void addExtraExportsOrOpens(Layer bootLayer, diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java index 3aac651577c..b58c717affe 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +37,6 @@ import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Opens; -import java.lang.module.ModuleDescriptor.Version; import java.nio.ByteBuffer; import java.nio.BufferUnderflowException; import java.util.ArrayList; @@ -51,7 +50,6 @@ import java.util.function.Supplier; import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; -import jdk.internal.module.ModuleResolution; import static jdk.internal.module.ClassFileConstants.*; @@ -221,7 +219,7 @@ public final class ModuleInfo { Set attributes = new HashSet<>(); Builder builder = null; - Set packages = null; + Set allPackages = null; String mainClass = null; String[] osValues = null; ModuleHashes hashes = null; @@ -245,7 +243,7 @@ public final class ModuleInfo { break; case MODULE_PACKAGES : - packages = readModulePackagesAttribute(in, cpool); + allPackages = readModulePackagesAttribute(in, cpool); break; case MODULE_MAIN_CLASS : @@ -284,51 +282,44 @@ public final class ModuleInfo { throw invalidModuleDescriptor(MODULE + " attribute not found"); } + // ModuleMainClass and ModuleTarget attributes + if (mainClass != null) { + builder.mainClass(mainClass); + } + if (osValues != null) { + if (osValues[0] != null) builder.osName(osValues[0]); + if (osValues[1] != null) builder.osArch(osValues[1]); + if (osValues[2] != null) builder.osVersion(osValues[2]); + } + // If the ModulePackages attribute is not present then the packageFinder // is used to find the set of packages boolean usedPackageFinder = false; - if (packages == null && packageFinder != null) { + if (allPackages == null && packageFinder != null) { try { - packages = new HashSet<>(packageFinder.get()); + allPackages = packageFinder.get(); } catch (UncheckedIOException x) { throw x.getCause(); } usedPackageFinder = true; } - if (packages != null) { - Set exportedPackages = JLMA.exportedPackages(builder); - Set openPackages = JLMA.openPackages(builder); - if (packages.containsAll(exportedPackages) - && packages.containsAll(openPackages)) { - packages.removeAll(exportedPackages); - packages.removeAll(openPackages); - } else { - // the set of packages is not complete - Set exportedAndOpenPackages = new HashSet<>(); - exportedAndOpenPackages.addAll(exportedPackages); - exportedAndOpenPackages.addAll(openPackages); - for (String pn : exportedAndOpenPackages) { - if (!packages.contains(pn)) { - String tail; - if (usedPackageFinder) { - tail = " not found by package finder"; - } else { - tail = " missing from ModulePackages attribute"; - } - throw invalidModuleDescriptor("Package " + pn + tail); - } + if (allPackages != null) { + Set knownPackages = JLMA.packages(builder); + if (!allPackages.containsAll(knownPackages)) { + Set missingPackages = new HashSet<>(knownPackages); + missingPackages.removeAll(allPackages); + assert !missingPackages.isEmpty(); + String missingPackage = missingPackages.iterator().next(); + String tail; + if (usedPackageFinder) { + tail = " not found in module"; + } else { + tail = " missing from ModulePackages class file attribute"; } - assert false; // should not get here - } - builder.contains(packages); - } + throw invalidModuleDescriptor("Package " + missingPackage + tail); - if (mainClass != null) - builder.mainClass(mainClass); - if (osValues != null) { - if (osValues[0] != null) builder.osName(osValues[0]); - if (osValues[1] != null) builder.osArch(osValues[1]); - if (osValues[2] != null) builder.osVersion(osValues[2]); + } + builder.packages(allPackages); } ModuleDescriptor descriptor = builder.build(); @@ -347,10 +338,17 @@ public final class ModuleInfo { String mn = cpool.getModuleName(module_name_index); int module_flags = in.readUnsignedShort(); - boolean open = ((module_flags & ACC_OPEN) != 0); - boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0); - Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic); + Set modifiers = new HashSet<>(); + boolean open = ((module_flags & ACC_OPEN) != 0); + if (open) + modifiers.add(ModuleDescriptor.Modifier.OPEN); + if ((module_flags & ACC_SYNTHETIC) != 0) + modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC); + if ((module_flags & ACC_MANDATED) != 0) + modifiers.add(ModuleDescriptor.Modifier.MANDATED); + + Builder builder = JLMA.newModuleBuilder(mn, false, modifiers); int module_version_index = in.readUnsignedShort(); if (module_version_index != 0) { @@ -381,16 +379,11 @@ public final class ModuleInfo { } int requires_version_index = in.readUnsignedShort(); - Version compiledVersion = null; - if (requires_version_index != 0) { - String vs = cpool.getUtf8(requires_version_index); - compiledVersion = Version.parse(vs); - } - - if (compiledVersion == null) { + if (requires_version_index == 0) { builder.requires(mods, dn); } else { - builder.requires(mods, dn, compiledVersion); + String vs = cpool.getUtf8(requires_version_index); + JLMA.requires(builder, mods, dn, vs); } if (dn.equals("java.base")) @@ -629,10 +622,7 @@ public final class ModuleInfo { /** * Return true if the given attribute name is the name of a pre-defined - * attribute that is not allowed in the class file. - * - * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and - * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear. + * attribute in JVMS 4.7 that is not allowed in a module-info class. */ private static boolean isAttributeDisallowed(String name) { Set notAllowed = predefinedNotAllowed; @@ -640,6 +630,7 @@ public final class ModuleInfo { notAllowed = Set.of( "ConstantValue", "Code", + "Deprecated", "StackMapTable", "Exceptions", "EnclosingMethod", diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java index 0d05ad296e9..73fb660ed7f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java @@ -56,7 +56,7 @@ public final class ModuleInfoExtender { // the packages in the ModulePackages attribute private Set packages; - // the value of the module_version in Module attribute + // the value for the module version in the Module attribute private Version version; // the value of the ModuleMainClass attribute @@ -78,7 +78,11 @@ public final class ModuleInfoExtender { } /** - * Sets the set of packages for the ModulePackages attribute + * Sets the packages for the ModulePackages attribute + * + * @apiNote This method does not check that the package names are legal + * package names or that the set of packages is a super set of the + * packages in the module. */ public ModuleInfoExtender packages(Set packages) { this.packages = Collections.unmodifiableSet(packages); @@ -86,7 +90,7 @@ public final class ModuleInfoExtender { } /** - * Sets the value of the module_version in Module attribute. + * Sets the value for the module version in the Module attribute */ public ModuleInfoExtender version(Version version) { this.version = version; @@ -95,6 +99,9 @@ public final class ModuleInfoExtender { /** * Sets the value of the ModuleMainClass attribute. + * + * @apiNote This method does not check that the main class is a legal + * class name in a named package. */ public ModuleInfoExtender mainClass(String mainClass) { this.mainClass = mainClass; @@ -133,7 +140,7 @@ public final class ModuleInfoExtender { /** * A ClassVisitor that supports adding class file attributes. If an - * attribute already exists then the first occurence of the attribute + * attribute already exists then the first occurrence of the attribute * is replaced. */ private static class AttributeAddingClassVisitor extends ClassVisitor { diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java index 9c3308f97a0..15e60d0d611 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,13 +41,6 @@ import jdk.internal.loader.ClassLoaders; * are generated at build time. */ final class ModuleLoaderMap { - /* - * The list of boot modules and platform modules are generated at build time. - */ - private static final String[] BOOT_MODULES - = new String[] { "@@BOOT_MODULE_NAMES@@" }; - private static final String[] PLATFORM_MODULES - = new String[] { "@@PLATFORM_MODULE_NAMES@@" }; /** * Returns the function to map modules in the given configuration to the @@ -55,6 +48,10 @@ final class ModuleLoaderMap { */ static Function mappingFunction(Configuration cf) { + // The list of boot modules and platform modules are generated at build time. + final String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" }; + final String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" }; + Set bootModules = new HashSet<>(BOOT_MODULES.length); for (String mn : BOOT_MODULES) { bootModules.add(mn); diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java index 5bd7ef5ed04..fe3f8930ad2 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.net.MalformedURLException; @@ -54,6 +55,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.internal.loader.Resource; +import jdk.internal.loader.ResourceHelper; import jdk.internal.misc.JavaLangModuleAccess; import jdk.internal.misc.SharedSecrets; import sun.net.www.ParseUtil; @@ -108,8 +110,11 @@ public final class ModulePatcher { if (paths == null) return mref; - // scan the JAR file or directory tree to get the set of packages + // Scan the JAR file or directory tree to get the set of packages. + // For automatic modules then packages that do not contain class files + // must be ignored. Set packages = new HashSet<>(); + boolean isAutomatic = descriptor.isAutomatic(); try { for (Path file : paths) { if (Files.isRegularFile(file)) { @@ -118,8 +123,10 @@ public final class ModulePatcher { // is not supported by the boot class loader try (JarFile jf = new JarFile(file.toFile())) { jf.stream() + .filter(e -> !e.isDirectory() + && (!isAutomatic || e.getName().endsWith(".class"))) .map(e -> toPackageName(file, e)) - .filter(Checks::isJavaIdentifier) + .filter(Checks::isPackageName) .forEach(packages::add); } @@ -129,8 +136,10 @@ public final class ModulePatcher { Path top = file; Files.find(top, Integer.MAX_VALUE, ((path, attrs) -> attrs.isRegularFile())) + .filter(path -> !isAutomatic + || path.toString().endsWith(".class")) .map(path -> toPackageName(top, path)) - .filter(Checks::isJavaIdentifier) + .filter(Checks::isPackageName) .forEach(packages::add); } @@ -141,10 +150,30 @@ public final class ModulePatcher { } // if there are new packages then we need a new ModuleDescriptor - Set original = descriptor.packages(); - packages.addAll(original); - if (packages.size() > original.size()) { - descriptor = JLMA.newModuleDescriptor(descriptor, packages); + packages.removeAll(descriptor.packages()); + if (!packages.isEmpty()) { + Builder builder = JLMA.newModuleBuilder(descriptor.name(), + /*strict*/ false, + descriptor.modifiers()); + if (!descriptor.isAutomatic()) { + descriptor.requires().forEach(builder::requires); + descriptor.exports().forEach(builder::exports); + descriptor.opens().forEach(builder::opens); + descriptor.uses().forEach(builder::uses); + } + descriptor.provides().forEach(builder::provides); + + descriptor.version().ifPresent(builder::version); + descriptor.mainClass().ifPresent(builder::mainClass); + descriptor.osName().ifPresent(builder::osName); + descriptor.osArch().ifPresent(builder::osArch); + descriptor.osVersion().ifPresent(builder::osVersion); + + // original + new packages + builder.packages(descriptor.packages()); + builder.packages(packages); + + descriptor = builder.build(); } // return a module reference to the patched module @@ -471,23 +500,14 @@ public final class ModulePatcher { @Override public Resource find(String name) throws IOException { - Path file = Paths.get(name.replace('/', File.separatorChar)); - if (file.getRoot() == null) { - file = dir.resolve(file); - } else { - // drop the root component so that the resource is - // located relative to the module directory - int n = file.getNameCount(); - if (n == 0) - return null; - file = dir.resolve(file.subpath(0, n)); - } - - if (Files.isRegularFile(file)) { - return newResource(name, dir, file); - } else { - return null; + Path path = ResourceHelper.toFilePath(name); + if (path != null) { + Path file = dir.resolve(path); + if (Files.isRegularFile(file)) { + return newResource(name, dir, file); + } } + return null; } private Resource newResource(String name, Path top, Path file) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java index fb7871d3c31..ae337423965 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ import java.io.UncheckedIOException; import java.lang.module.FindException; import java.lang.module.InvalidModuleDescriptorException; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.net.URI; @@ -70,12 +69,11 @@ import jdk.internal.util.jar.VersionedStream; /** * A {@code ModuleFinder} that locates modules on the file system by searching - * a sequence of directories or packaged modules. - * - * The {@code ModuleFinder} can be created to work in either the run-time - * or link-time phases. In both cases it locates modular JAR and exploded - * modules. When created for link-time then it additionally locates - * modules in JMOD files. + * a sequence of directories or packaged modules. The ModuleFinder can be + * created to work in either the run-time or link-time phases. In both cases it + * locates modular JAR and exploded modules. When created for link-time then it + * additionally locates modules in JMOD files. The ModuleFinder can also + * optionally patch any modules that it locates with a ModulePatcher. */ public class ModulePath implements ModuleFinder { @@ -87,6 +85,9 @@ public class ModulePath implements ModuleFinder { // true for the link phase (supports modules packaged in JMOD format) private final boolean isLinkPhase; + // for patching modules, can be null + private final ModulePatcher patcher; + // the entries on this module path private final Path[] entries; private int next; @@ -94,19 +95,51 @@ public class ModulePath implements ModuleFinder { // map of module name to module reference map for modules already located private final Map cachedModules = new HashMap<>(); - public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) { + + private ModulePath(Runtime.Version version, + boolean isLinkPhase, + ModulePatcher patcher, + Path... entries) { this.releaseVersion = version; this.isLinkPhase = isLinkPhase; + this.patcher = patcher; this.entries = entries.clone(); for (Path entry : this.entries) { Objects.requireNonNull(entry); } } - public ModulePath(Path... entries) { - this(JarFile.runtimeVersion(), false, entries); + /** + * Returns a ModuleFinder that that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. The modules + * may be patched by the given ModulePatcher. + */ + public static ModuleFinder of(ModulePatcher patcher, Path... entries) { + return new ModulePath(JarFile.runtimeVersion(), false, patcher, entries); } + /** + * Returns a ModuleFinder that that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. + */ + public static ModuleFinder of(Path... entries) { + return of((ModulePatcher)null, entries); + } + + /** + * Returns a ModuleFinder that that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. + * + * @param version The release version to use for multi-release JAR files + * @param isLinkPhase {@code true} if the link phase to locate JMOD files + */ + public static ModuleFinder of(Runtime.Version version, + boolean isLinkPhase, + Path... entries) { + return new ModulePath(version, isLinkPhase, null, entries); + } + + @Override public Optional find(String name) { Objects.requireNonNull(name); @@ -195,8 +228,7 @@ public class ModulePath implements ModuleFinder { if (attrs.isDirectory()) { Path mi = entry.resolve(MODULE_INFO); if (!Files.exists(mi)) { - // does not exist or unable to determine so assume a - // directory of modules + // assume a directory of modules return scanDirectory(entry); } } @@ -206,11 +238,17 @@ public class ModulePath implements ModuleFinder { if (mref != null) { String name = mref.descriptor().name(); return Collections.singletonMap(name, mref); - } else { - // skipped - return Collections.emptyMap(); } + // not recognized + String msg; + if (!isLinkPhase && entry.toString().endsWith(".jmod")) { + msg = "JMOD format not supported at execution time"; + } else { + msg = "Module format not recognized"; + } + throw new FindException(msg + ": " + entry); + } catch (IOException ioe) { throw new FindException(ioe); } @@ -266,14 +304,11 @@ public class ModulePath implements ModuleFinder { /** - * Locates a packaged or exploded module, returning a {@code ModuleReference} - * to the module. Returns {@code null} if the entry is skipped because it is - * to a directory that does not contain a module-info.class or it's a hidden - * file. + * Reads a packaged or exploded module, returning a {@code ModuleReference} + * to the module. Returns {@code null} if the entry is not recognized. * * @throws IOException if an I/O error occurs - * @throws FindException if the file is not recognized as a module or an - * error occurs parsing its module descriptor + * @throws FindException if an error occurs parsing its module descriptor */ private ModuleReference readModule(Path entry, BasicFileAttributes attrs) throws IOException @@ -282,24 +317,16 @@ public class ModulePath implements ModuleFinder { if (attrs.isDirectory()) { return readExplodedModule(entry); // may return null - } - - String fn = entry.getFileName().toString(); - if (attrs.isRegularFile()) { - if (fn.endsWith(".jar")) { - return readJar(entry); - } else if (fn.endsWith(".jmod")) { - if (isLinkPhase) - return readJMod(entry); - throw new FindException("JMOD files not supported: " + entry); - } - } - - // skip hidden files - if (fn.startsWith(".") || Files.isHidden(entry)) { - return null; } else { - throw new FindException("Unrecognized module: " + entry); + String fn = entry.getFileName().toString(); + if (attrs.isRegularFile()) { + if (fn.endsWith(".jar")) { + return readJar(entry); + } else if (isLinkPhase && fn.endsWith(".jmod")) { + return readJMod(entry); + } + } + return null; } } catch (InvalidModuleDescriptorException e) { @@ -327,7 +354,7 @@ public class ModulePath implements ModuleFinder { } } - // -- jmod files -- + // -- JMOD files -- private Set jmodPackages(JmodFile jf) { return jf.stream() @@ -339,7 +366,7 @@ public class ModulePath implements ModuleFinder { } /** - * Returns a {@code ModuleReference} to a module in jmod file on the + * Returns a {@code ModuleReference} to a module in JMOD file on the * file system. * * @throws IOException @@ -362,7 +389,7 @@ public class ModulePath implements ModuleFinder { /** * Returns the service type corresponding to the name of a services - * configuration file if it is a valid Java identifier. + * configuration file if it is a legal type name. * * For example, if called with "META-INF/services/p.S" then this method * returns a container with the value "p.S". @@ -374,7 +401,7 @@ public class ModulePath implements ModuleFinder { String prefix = cf.substring(0, index); if (prefix.equals(SERVICES_PREFIX)) { String sn = cf.substring(index); - if (Checks.isJavaIdentifier(sn)) + if (Checks.isClassName(sn)) return Optional.of(sn); } } @@ -403,11 +430,10 @@ public class ModulePath implements ModuleFinder { * * 1. The module name (and optionally the version) is derived from the file * name of the JAR file - * 2. All packages are exported and open - * 3. It has no non-exported/non-open packages - * 4. The contents of any META-INF/services configuration files are mapped + * 2. All packages are derived from the .class files in the JAR file + * 3. The contents of any META-INF/services configuration files are mapped * to "provides" declarations - * 5. The Main-Class attribute in the main attributes of the JAR manifest + * 4. The Main-Class attribute in the main attributes of the JAR manifest * is mapped to the module descriptor mainClass */ private ModuleDescriptor deriveModuleDescriptor(JarFile jf) @@ -443,9 +469,7 @@ public class ModulePath implements ModuleFinder { mn = cleanModuleName(mn); // Builder throws IAE if module name is empty or invalid - ModuleDescriptor.Builder builder - = ModuleDescriptor.automaticModule(mn) - .requires(Set.of(Requires.Modifier.MANDATED), "java.base"); + ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(mn); if (vs != null) builder.version(vs); @@ -453,17 +477,22 @@ public class ModulePath implements ModuleFinder { Map> map = VersionedStream.stream(jf) .filter(e -> !e.isDirectory()) .map(JarEntry::getName) + .filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX))) .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX), Collectors.toSet())); - Set resources = map.get(Boolean.FALSE); + Set classFiles = map.get(Boolean.FALSE); Set configFiles = map.get(Boolean.TRUE); - // all packages are exported and open - resources.stream() + + // the packages containing class files + Set packages = classFiles.stream() .map(this::toPackageName) .flatMap(Optional::stream) .distinct() - .forEach(pn -> builder.exports(pn).opens(pn)); + .collect(Collectors.toSet()); + + // all packages are exported and open + builder.packages(packages); // map names of service configuration files to service names Set serviceNames = configFiles.stream() @@ -481,6 +510,11 @@ public class ModulePath implements ModuleFinder { String cn; while ((cn = nextLine(reader)) != null) { if (cn.length() > 0) { + String pn = packageName(cn); + if (!packages.contains(pn)) { + String msg = "Provider class " + cn + " not in module"; + throw new IOException(msg); + } providerClasses.add(cn); } } @@ -494,8 +528,15 @@ public class ModulePath implements ModuleFinder { if (man != null) { Attributes attrs = man.getMainAttributes(); String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS); - if (mainClass != null) - builder.mainClass(mainClass.replace("/", ".")); + if (mainClass != null) { + mainClass = mainClass.replace("/", "."); + String pn = packageName(mainClass); + if (!packages.contains(pn)) { + String msg = "Main-Class " + mainClass + " not in module"; + throw new IOException(msg); + } + builder.mainClass(mainClass); + } } return builder.build(); @@ -569,10 +610,10 @@ public class ModulePath implements ModuleFinder { try { ModuleDescriptor md = deriveModuleDescriptor(jf); attrs = new ModuleInfo.Attributes(md, null, null); - } catch (IllegalArgumentException iae) { + } catch (IllegalArgumentException e) { throw new FindException( "Unable to derive module descriptor for: " - + jf.getName(), iae); + + jf.getName(), e); } } else { @@ -580,7 +621,7 @@ public class ModulePath implements ModuleFinder { () -> jarPackages(jf)); } - return ModuleReferences.newJarModule(attrs, file); + return ModuleReferences.newJarModule(attrs, patcher, file); } } @@ -617,7 +658,15 @@ public class ModulePath implements ModuleFinder { // for now return null; } - return ModuleReferences.newExplodedModule(attrs, dir); + return ModuleReferences.newExplodedModule(attrs, patcher, dir); + } + + /** + * Maps a type name to its package name. + */ + private static String packageName(String cn) { + int index = cn.lastIndexOf('.'); + return (index == -1) ? "" : cn.substring(0, index); } /** @@ -629,19 +678,18 @@ public class ModulePath implements ModuleFinder { */ private Optional toPackageName(String name) { assert !name.endsWith("/"); - int index = name.lastIndexOf("/"); if (index == -1) { if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { throw new IllegalArgumentException(name - + " found in top-level directory:" + + " found in top-level directory" + " (unnamed package not allowed in module)"); } return Optional.empty(); } String pn = name.substring(0, index).replace('/', '.'); - if (Checks.isJavaIdentifier(pn)) { + if (Checks.isPackageName(pn)) { return Optional.of(pn); } else { // not a valid package name @@ -654,7 +702,7 @@ public class ModulePath implements ModuleFinder { * name. * * @throws IllegalArgumentException if the name is a class file in - * the top-level directory (and it's not module-info.class) + * the top-level directory (and it's not module-info.class) */ private Optional toPackageName(Path file) { assert file.getRoot() == null; @@ -664,14 +712,14 @@ public class ModulePath implements ModuleFinder { String name = file.toString(); if (name.endsWith(".class") && !name.equals(MODULE_INFO)) { throw new IllegalArgumentException(name - + " found in in top-level directory" + + " found in top-level directory" + " (unnamed package not allowed in module)"); } return Optional.empty(); } String pn = parent.toString().replace(File.separatorChar, '.'); - if (Checks.isJavaIdentifier(pn)) { + if (Checks.isPackageName(pn)) { return Optional.of(pn); } else { // not a valid package name diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java index 2ab42bdb4a2..f861b294aef 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java @@ -163,7 +163,14 @@ public class ModuleReferenceImpl extends ModuleReference { @Override public String toString() { - return super.toString(); + StringBuilder sb = new StringBuilder(); + sb.append("[module "); + sb.append(descriptor().name()); + sb.append(", location="); + sb.append(location().orElseThrow(() -> new InternalError())); + if (isPatched()) sb.append(" (patched)"); + sb.append("]"); + return sb.toString(); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java index a2aff8f76be..2e2af727599 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java @@ -36,7 +36,6 @@ import java.net.URI; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -51,7 +50,7 @@ import java.util.stream.Stream; import java.util.zip.ZipFile; import jdk.internal.jmod.JmodFile; -import jdk.internal.misc.JavaLangAccess; +import jdk.internal.loader.ResourceHelper; import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ModuleHashes.HashSupplier; import jdk.internal.util.jar.VersionedStream; @@ -65,20 +64,16 @@ import sun.net.www.ParseUtil; */ class ModuleReferences { - - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - private ModuleReferences() { } /** - * Creates a ModuleReference to a module or to patched module when - * creating modules for the boot Layer and --patch-module is specified. + * Creates a ModuleReference to a possibly-patched module */ private static ModuleReference newModule(ModuleInfo.Attributes attrs, URI uri, Supplier supplier, + ModulePatcher patcher, HashSupplier hasher) { - ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(), uri, supplier, @@ -86,38 +81,42 @@ class ModuleReferences { attrs.recordedHashes(), hasher, attrs.moduleResolution()); - if (JLA.getBootLayer() == null) - mref = ModuleBootstrap.patcher().patchIfNeeded(mref); + if (patcher != null) + mref = patcher.patchIfNeeded(mref); return mref; } /** - * Creates a ModuleReference to a module packaged as a modular JAR. + * Creates a ModuleReference to a possibly-patched module in a modular JAR. */ - static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) { + static ModuleReference newJarModule(ModuleInfo.Attributes attrs, + ModulePatcher patcher, + Path file) { URI uri = file.toUri(); Supplier supplier = () -> new JarModuleReader(file, uri); HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a); - return newModule(attrs, uri, supplier, hasher); + return newModule(attrs, uri, supplier, patcher, hasher); } /** - * Creates a ModuleReference to a module packaged as a JMOD. + * Creates a ModuleReference to a module in a JMOD file. */ static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) { URI uri = file.toUri(); Supplier supplier = () -> new JModModuleReader(file, uri); HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a); - return newModule(attrs, uri, supplier, hasher); + return newModule(attrs, uri, supplier, null, hasher); } /** - * Creates a ModuleReference to an exploded module. + * Creates a ModuleReference to a possibly-patched exploded module. */ - static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) { + static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, + ModulePatcher patcher, + Path dir) { Supplier supplier = () -> new ExplodedModuleReader(dir); - return newModule(attrs, dir.toUri(), supplier, null); + return newModule(attrs, dir.toUri(), supplier, patcher, null); } @@ -243,7 +242,8 @@ class ModuleReferences { } private JarEntry getEntry(String name) { - return jf.getJarEntry(Objects.requireNonNull(name)); + JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name)); + return (entry == null || entry.isDirectory()) ? null : entry; } @Override @@ -369,21 +369,6 @@ class ModuleReferences { } } - /** - * Returns a Path to access to the given resource. - */ - private Path toPath(String name) { - Path path = Paths.get(name.replace('/', File.separatorChar)); - if (path.getRoot() == null) { - return dir.resolve(path); - } else { - // drop the root component so that the resource is - // located relative to the module directory - int n = path.getNameCount(); - return (n > 0) ? dir.resolve(path.subpath(0, n)) : null; - } - } - /** * Throws IOException if the module reader is closed; */ @@ -391,11 +376,27 @@ class ModuleReferences { if (closed) throw new IOException("ModuleReader is closed"); } + /** + * Returns a Path to access the given resource. Returns null if the + * resource name does not convert to a file path that locates a regular + * file in the module. + */ + private Path toFilePath(String name) { + Path path = ResourceHelper.toFilePath(name); + if (path != null) { + Path file = dir.resolve(path); + if (Files.isRegularFile(file)) { + return file; + } + } + return null; + } + @Override public Optional find(String name) throws IOException { ensureOpen(); - Path path = toPath(name); - if (path != null && Files.isRegularFile(path)) { + Path path = toFilePath(name); + if (path != null) { try { return Optional.of(path.toUri()); } catch (IOError e) { @@ -409,8 +410,8 @@ class ModuleReferences { @Override public Optional open(String name) throws IOException { ensureOpen(); - Path path = toPath(name); - if (path != null && Files.isRegularFile(path)) { + Path path = toFilePath(name); + if (path != null) { return Optional.of(Files.newInputStream(path)); } else { return Optional.empty(); @@ -420,8 +421,8 @@ class ModuleReferences { @Override public Optional read(String name) throws IOException { ensureOpen(); - Path path = toPath(name); - if (path != null && Files.isRegularFile(path)) { + Path path = toFilePath(name); + if (path != null) { return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path))); } else { return Optional.empty(); diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java index 9f68cfbc421..485d2e130b5 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java @@ -82,8 +82,8 @@ public class Modules { String name, Set packages) { - ModuleDescriptor descriptor = ModuleDescriptor.module(name) - .contains(packages) + ModuleDescriptor descriptor = ModuleDescriptor.newModule(name) + .packages(packages) .build(); return JLRMA.defineModule(loader, descriptor, null); @@ -185,7 +185,8 @@ public class Modules { /** * Adds a package to a module's content. * - * This method is a no-op if the module already contains the package. + * This method is a no-op if the module already contains the package or the + * module is an unnamed module. */ public static void addPackage(Module m, String pn) { JLRMA.addPackage(m, pn); diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java index 5ec0a62ca69..a7ee7ffe74f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java @@ -80,8 +80,6 @@ public class SystemModuleFinder implements ModuleFinder { = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages"); private static final PerfCounter exportsCount = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports"); - // ImageReader used to access all modules in the image - private static final ImageReader imageReader; // singleton finder to find modules in the run-time images private static final SystemModuleFinder INSTANCE; @@ -96,13 +94,28 @@ public class SystemModuleFinder implements ModuleFinder { */ static { long t0 = System.nanoTime(); - imageReader = ImageReaderFactory.getImageReader(); INSTANCE = new SystemModuleFinder(); initTime.addElapsedTimeFrom(t0); } + /** + * Holder class for the ImageReader + */ + private static class SystemImage { + static final ImageReader READER; + static { + long t0 = System.nanoTime(); + READER = ImageReaderFactory.getImageReader(); + initTime.addElapsedTimeFrom(t0); + } + + static ImageReader reader() { + return READER; + } + } + private static boolean isFastPathSupported() { return SystemModules.MODULE_NAMES.length > 0; } @@ -114,7 +127,7 @@ public class SystemModuleFinder implements ModuleFinder { // this happens when java.base is patched with java.base // from an exploded image - return imageReader.getModuleNames(); + return SystemImage.reader().getModuleNames(); } // the set of modules in the run-time image @@ -151,6 +164,7 @@ public class SystemModuleFinder implements ModuleFinder { descriptors = new ModuleDescriptor[n]; recordedHashes = new ModuleHashes[n]; moduleResolutions = new ModuleResolution[n]; + ImageReader imageReader = SystemImage.reader(); for (int i = 0; i < names.length; i++) { String mn = names[i]; ImageLocation loc = imageReader.findLocation(mn, "module-info.class"); @@ -291,6 +305,7 @@ public class SystemModuleFinder implements ModuleFinder { Objects.requireNonNull(name); if (closed) throw new IOException("ModuleReader is closed"); + ImageReader imageReader = SystemImage.reader(); if (imageReader != null) { return imageReader.findLocation(module, name); } else { @@ -330,7 +345,7 @@ public class SystemModuleFinder implements ModuleFinder { public Optional read(String name) throws IOException { ImageLocation location = findImageLocation(name); if (location != null) { - return Optional.of(imageReader.getResourceBuffer(location)); + return Optional.of(SystemImage.reader().getResourceBuffer(location)); } else { return Optional.empty(); } @@ -372,7 +387,7 @@ public class SystemModuleFinder implements ModuleFinder { stack = new ArrayDeque<>(); // push the root node to the stack to get started - ImageReader.Node dir = imageReader.findNode(moduleRoot); + ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot); if (dir == null || !dir.isDirectory()) throw new IOException(moduleRoot + " not a directory"); stack.push(dir); @@ -390,7 +405,7 @@ public class SystemModuleFinder implements ModuleFinder { String name = node.getName(); if (node.isDirectory()) { // build node - ImageReader.Node dir = imageReader.findNode(name); + ImageReader.Node dir = SystemImage.reader().findNode(name); assert dir.isDirectory(); stack.push(dir); } else { diff --git a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index 9a410049188..61969590d92 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,15 +211,7 @@ public class Reflection { if (currentModule == memberModule) return true; // same module (named or unnamed) - // memberClass may be primitive or array class - Class c = memberClass; - while (c.isArray()) { - c = c.getComponentType(); - } - if (c.isPrimitive()) - return true; - - String pkg = c.getPackageName(); + String pkg = memberClass.getPackageName(); boolean allowed = memberModule.isExported(pkg, currentModule); if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) { if (!SharedSecrets.getJavaLangReflectModuleAccess() @@ -237,10 +229,6 @@ public class Reflection { private static boolean isSameClassPackage(Class c1, Class c2) { if (c1.getClassLoader() != c2.getClassLoader()) return false; - while (c1.isArray()) - c1 = c1.getComponentType(); - while (c2.isArray()) - c2 = c2.getComponentType(); return Objects.equals(c1.getPackageName(), c2.getPackageName()); } @@ -378,12 +366,6 @@ public class Reflection { } } - public static void enableStackTraces() { - printStackWhenAccessFails = true; - printStackWhenAccessSucceeds = true; - printStackPropertiesSet = true; - } - public static boolean printStackTraceWhenAccessFails() { ensurePrintStackPropertiesSet(); return printStackWhenAccessFails; @@ -413,11 +395,7 @@ public class Reflection { if (m2.isNamed()) memberSuffix = " (in " + m2 + ")"; - Class c = memberClass; - while (c.isArray()) { - c = c.getComponentType(); - } - String memberPackageName = c.getPackageName(); + String memberPackageName = memberClass.getPackageName(); String msg = currentClass + currentSuffix + " cannot access "; if (m2.isExported(memberPackageName, m1)) { diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java index 185f8f2a1d1..3ad3f4a096c 100644 --- a/jdk/src/java.base/share/classes/module-info.java +++ b/jdk/src/java.base/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the foundational APIs of the Java SE Platform. + * + * @since 9 */ module java.base { diff --git a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java index 9c46aad018f..c3633ff8aab 100644 --- a/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java +++ b/jdk/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,6 +39,7 @@ public class VerifyAccess { private VerifyAccess() { } // cannot instantiate + private static final int UNCONDITIONAL_ALLOWED = java.lang.invoke.MethodHandles.Lookup.UNCONDITIONAL; private static final int MODULE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.MODULE; private static final int PACKAGE_ONLY = 0; private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE; @@ -92,7 +93,7 @@ public class VerifyAccess { int allowedModes) { if (allowedModes == 0) return false; assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0); + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); // The symbolic reference class (refc) must always be fully verified. if (!isClassAccessible(refc, lookupClass, allowedModes)) { return false; @@ -173,7 +174,7 @@ public class VerifyAccess { int allowedModes) { if (allowedModes == 0) return false; assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0); + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0); int mods = getClassModifiers(refc); if (isPublic(mods)) { @@ -191,22 +192,17 @@ public class VerifyAccess { (lookupModule == refModule)) return true; - // check readability - if (lookupModule.canRead(refModule)) { + // check readability when UNCONDITIONAL not allowed + if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0) + || lookupModule.canRead(refModule)) { // check that refc is in an exported package - Class c = refc; - while (c.isArray()) { - c = c.getComponentType(); - } - if (c.isPrimitive()) - return true; if ((allowedModes & MODULE_ALLOWED) != 0) { - if (refModule.isExported(c.getPackageName(), lookupModule)) + if (refModule.isExported(refc.getPackageName(), lookupModule)) return true; } else { // exported unconditionally - if (refModule.isExported(c.getPackageName())) + if (refModule.isExported(refc.getPackageName())) return true; } diff --git a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java index ee8f311d2e4..39df984054b 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -591,8 +591,8 @@ public final class LauncherHelper { c = Class.forName(m, cn); } } catch (LinkageError le) { - abort(null, "java.launcher.module.error3", - mainClass, m.getName(), le.getLocalizedMessage()); + abort(null, "java.launcher.module.error3", mainClass, m.getName(), + le.getClass().getName() + ": " + le.getLocalizedMessage()); } if (c == null) { abort(null, "java.launcher.module.error2", mainClass, mainModule); @@ -645,7 +645,8 @@ public final class LauncherHelper { } } } catch (LinkageError le) { - abort(le, "java.launcher.cls.error6", cn, le.getLocalizedMessage()); + abort(le, "java.launcher.cls.error6", cn, + le.getClass().getName() + ": " + le.getLocalizedMessage()); } return mainClass; } @@ -966,6 +967,10 @@ public final class LauncherHelper { ostream.print("open "); if (md.isAutomatic()) ostream.print("automatic "); + if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) + ostream.print("synthetic "); + if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED)) + ostream.print("mandated "); ostream.println("module " + midAndLocation(md, mref.location())); // unqualified exports (sorted by package) diff --git a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java index 88e6f5b7caa..893bb55c10a 100644 --- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java @@ -32,7 +32,9 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; +import java.security.AccessController; import java.security.Permission; +import java.security.PrivilegedAction; import jdk.internal.jimage.ImageLocation; import jdk.internal.jimage.ImageReader; @@ -51,7 +53,11 @@ import sun.security.action.GetPropertyAction; public class JavaRuntimeURLConnection extends URLConnection { // ImageReader to access resources in jimage - private static final ImageReader reader = ImageReaderFactory.getImageReader(); + private static final ImageReader reader; + static { + PrivilegedAction pa = ImageReaderFactory::getImageReader; + reader = AccessController.doPrivileged(pa); + } // the module and resource name in the URL private final String module; diff --git a/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java index ed69ba3d8b9..6efd90d0670 100644 --- a/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java +++ b/jdk/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +37,7 @@ import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.Timestamp; +import java.security.cert.CertPathValidatorException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.CertPath; @@ -48,6 +49,7 @@ import java.util.EnumSet; import java.util.Set; import sun.security.timestamp.TimestampToken; +import sun.security.util.ConstraintsParameters; import sun.security.util.Debug; import sun.security.util.DerEncoder; import sun.security.util.DerInputStream; @@ -321,6 +323,8 @@ public class SignerInfo implements DerEncoder { data = content.getContentBytes(); } + ConstraintsParameters cparams = + new ConstraintsParameters(timestamp); String digestAlgname = getDigestAlgorithmId().getName(); byte[] dataSigned; @@ -347,11 +351,11 @@ public class SignerInfo implements DerEncoder { if (messageDigest == null) // fail if there is no message digest return null; - // check that algorithm is not restricted - if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, - digestAlgname, null)) { - throw new SignatureException("Digest check failed. " + - "Disabled algorithm used: " + digestAlgname); + // check that digest algorithm is not restricted + try { + JAR_DISABLED_CHECK.permits(digestAlgname, cparams); + } catch (CertPathValidatorException e) { + throw new SignatureException(e.getMessage(), e); } MessageDigest md = MessageDigest.getInstance(digestAlgname); @@ -385,17 +389,18 @@ public class SignerInfo implements DerEncoder { String algname = AlgorithmId.makeSigAlg( digestAlgname, encryptionAlgname); - // check that algorithm is not restricted - if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) { - throw new SignatureException("Signature check failed. " + - "Disabled algorithm used: " + algname); + // check that jar signature algorithm is not restricted + try { + JAR_DISABLED_CHECK.permits(algname, cparams); + } catch (CertPathValidatorException e) { + throw new SignatureException(e.getMessage(), e); } X509Certificate cert = getCertificate(block); - PublicKey key = cert.getPublicKey(); if (cert == null) { return null; } + PublicKey key = cert.getPublicKey(); // check if the public key is restricted if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) { diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java index 90559598aee..a12484d0e20 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ package sun.security.provider.certpath; import java.security.AlgorithmConstraints; import java.security.CryptoPrimitive; import java.security.Timestamp; +import java.security.cert.CertPathValidator; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -53,9 +54,10 @@ import java.security.interfaces.DSAPublicKey; import java.security.spec.DSAPublicKeySpec; import sun.security.util.AnchorCertificates; -import sun.security.util.CertConstraintParameters; +import sun.security.util.ConstraintsParameters; import sun.security.util.Debug; import sun.security.util.DisabledAlgorithmConstraints; +import sun.security.validator.Validator; import sun.security.x509.X509CertImpl; import sun.security.x509.X509CRLImpl; import sun.security.x509.AlgorithmId; @@ -79,6 +81,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { private final Date pkixdate; private PublicKey prevPubKey; private final Timestamp jarTimestamp; + private final String variant; private static final Set SIGNATURE_PRIMITIVE_SET = Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); @@ -109,64 +112,36 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { * * @param anchor the trust anchor selected to validate the target * certificate + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - public AlgorithmChecker(TrustAnchor anchor) { - this(anchor, certPathDefaultConstraints, null); - } - - /** - * Create a new {@code AlgorithmChecker} with the - * given {@code TrustAnchor} and {@code AlgorithmConstraints}. - * - * @param anchor the trust anchor selected to validate the target - * certificate - * @param constraints the algorithm constraints (or null) - * - * @throws IllegalArgumentException if the {@code anchor} is null - */ - public AlgorithmChecker(TrustAnchor anchor, - AlgorithmConstraints constraints) { - this(anchor, constraints, null); - } - - /** - * Create a new {@code AlgorithmChecker} with the - * given {@code AlgorithmConstraints}. - *

    - * Note that this constructor will be used to check a certification - * path where the trust anchor is unknown, or a certificate list which may - * contain the trust anchor. This constructor is used by SunJSSE. - * - * @param constraints the algorithm constraints (or null) - */ - public AlgorithmChecker(AlgorithmConstraints constraints) { - this.prevPubKey = null; - this.trustedPubKey = null; - this.constraints = constraints; - this.pkixdate = null; - this.jarTimestamp = null; + public AlgorithmChecker(TrustAnchor anchor, String variant) { + this(anchor, certPathDefaultConstraints, null, variant); } /** * Create a new {@code AlgorithmChecker} with the given - * {@code Timestamp}. + * {@code AlgorithmConstraints}, {@code Timestamp}, and/or {@code Variant}. *

    - * Note that this constructor will be used to check a certification - * path for signed JAR files that are timestamped. + * Note that this constructor can initialize a variation of situations where + * the AlgorithmConstraints, Timestamp, or Variant maybe known. * + * @param constraints the algorithm constraints (or null) * @param jarTimestamp Timestamp passed for JAR timestamp constraint * checking. Set to null if not applicable. + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - public AlgorithmChecker(Timestamp jarTimestamp) { + public AlgorithmChecker(AlgorithmConstraints constraints, + Timestamp jarTimestamp, String variant) { this.prevPubKey = null; this.trustedPubKey = null; - this.constraints = certPathDefaultConstraints; - if (jarTimestamp == null) { - throw new IllegalArgumentException( - "Timestamp cannot be null"); - } - this.pkixdate = jarTimestamp.getTimestamp(); + this.constraints = (constraints == null ? certPathDefaultConstraints : + constraints); + this.pkixdate = (jarTimestamp != null ? jarTimestamp.getTimestamp() : + null); this.jarTimestamp = jarTimestamp; + this.variant = (variant == null ? Validator.VAR_GENERIC : variant); } /** @@ -178,12 +153,13 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { * @param constraints the algorithm constraints (or null) * @param pkixdate Date the constraints are checked against. The value is * either the PKIXParameter date or null for the current date. + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. * * @throws IllegalArgumentException if the {@code anchor} is null */ public AlgorithmChecker(TrustAnchor anchor, - AlgorithmConstraints constraints, - Date pkixdate) { + AlgorithmConstraints constraints, Date pkixdate, String variant) { if (anchor != null) { if (anchor.getTrustedCert() != null) { @@ -207,6 +183,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { this.constraints = constraints; this.pkixdate = pkixdate; this.jarTimestamp = null; + this.variant = (variant == null ? Validator.VAR_GENERIC : variant); } /** @@ -217,11 +194,13 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { * certificate * @param pkixdate Date the constraints are checked against. The value is * either the PKIXParameter date or null for the current date. + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. * * @throws IllegalArgumentException if the {@code anchor} is null */ - public AlgorithmChecker(TrustAnchor anchor, Date pkixdate) { - this(anchor, certPathDefaultConstraints, pkixdate); + public AlgorithmChecker(TrustAnchor anchor, Date pkixdate, String variant) { + this(anchor, certPathDefaultConstraints, pkixdate, variant); } // Check this 'cert' for restrictions in the AnchorCertificates @@ -286,6 +265,28 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { null, null, -1, PKIXReason.INVALID_KEY_USAGE); } + X509CertImpl x509Cert; + AlgorithmId algorithmId; + try { + x509Cert = X509CertImpl.toImpl((X509Certificate)cert); + algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); + } catch (CertificateException ce) { + throw new CertPathValidatorException(ce); + } + + AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); + PublicKey currPubKey = cert.getPublicKey(); + String currSigAlg = x509Cert.getSigAlgName(); + + // Check the signature algorithm and parameters against constraints. + if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, currSigAlg, + currSigAlgParams)) { + throw new CertPathValidatorException( + "Algorithm constraints check failed on signature " + + "algorithm: " + currSigAlg, null, null, -1, + BasicReason.ALGORITHM_CONSTRAINED); + } + // Assume all key usage bits are set if key usage is not present Set primitives = KU_PRIMITIVE_SET; @@ -322,101 +323,74 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { } } - PublicKey currPubKey = cert.getPublicKey(); + ConstraintsParameters cp = + new ConstraintsParameters((X509Certificate)cert, + trustedMatch, pkixdate, jarTimestamp, variant); + // Check against local constraints if it is DisabledAlgorithmConstraints if (constraints instanceof DisabledAlgorithmConstraints) { - // Check against DisabledAlgorithmConstraints certpath constraints. - // permits() will throw exception on failure. - ((DisabledAlgorithmConstraints)constraints).permits(primitives, - new CertConstraintParameters((X509Certificate)cert, - trustedMatch, pkixdate, jarTimestamp)); - // If there is no previous key, set one and exit - if (prevPubKey == null) { - prevPubKey = currPubKey; - return; - } - } - - X509CertImpl x509Cert; - AlgorithmId algorithmId; - try { - x509Cert = X509CertImpl.toImpl((X509Certificate)cert); - algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG); - } catch (CertificateException ce) { - throw new CertPathValidatorException(ce); - } - - AlgorithmParameters currSigAlgParams = algorithmId.getParameters(); - String currSigAlg = x509Cert.getSigAlgName(); - - // If 'constraints' is not of DisabledAlgorithmConstraints, check all - // everything individually - if (!(constraints instanceof DisabledAlgorithmConstraints)) { - // Check the current signature algorithm - if (!constraints.permits( - SIGNATURE_PRIMITIVE_SET, - currSigAlg, currSigAlgParams)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed on signature " + - "algorithm: " + currSigAlg, null, null, -1, - BasicReason.ALGORITHM_CONSTRAINED); - } + ((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, cp); + // DisabledAlgorithmsConstraints does not check primitives, so key + // additional key check. + } else { + // Perform the default constraints checking anyway. + certPathDefaultConstraints.permits(currSigAlg, cp); + // Call locally set constraints to check key with primitives. if (!constraints.permits(primitives, currPubKey)) { throw new CertPathValidatorException( - "Algorithm constraints check failed on keysize: " + - sun.security.util.KeyUtil.getKeySize(currPubKey), + "Algorithm constraints check failed on key " + + currPubKey.getAlgorithm() + " with size of " + + sun.security.util.KeyUtil.getKeySize(currPubKey) + + "bits", null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } + // If there is no previous key, set one and exit + if (prevPubKey == null) { + prevPubKey = currPubKey; + return; + } + // Check with previous cert for signature algorithm and public key - if (prevPubKey != null) { - if (!constraints.permits( - SIGNATURE_PRIMITIVE_SET, - currSigAlg, prevPubKey, currSigAlgParams)) { - throw new CertPathValidatorException( + if (!constraints.permits( + SIGNATURE_PRIMITIVE_SET, + currSigAlg, prevPubKey, currSigAlgParams)) { + throw new CertPathValidatorException( "Algorithm constraints check failed on " + "signature algorithm: " + currSigAlg, null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } + + // Inherit key parameters from previous key + if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) { + // Inherit DSA parameters from previous key + if (!(prevPubKey instanceof DSAPublicKey)) { + throw new CertPathValidatorException("Input key is not " + + "of a appropriate type for inheriting parameters"); } - // Inherit key parameters from previous key - if (PKIX.isDSAPublicKeyWithoutParams(currPubKey)) { - // Inherit DSA parameters from previous key - if (!(prevPubKey instanceof DSAPublicKey)) { - throw new CertPathValidatorException("Input key is not " + - "of a appropriate type for inheriting parameters"); - } - - DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); - if (params == null) { - throw new CertPathValidatorException( + DSAParams params = ((DSAPublicKey)prevPubKey).getParams(); + if (params == null) { + throw new CertPathValidatorException( "Key parameters missing from public key."); - } + } - try { - BigInteger y = ((DSAPublicKey)currPubKey).getY(); - KeyFactory kf = KeyFactory.getInstance("DSA"); - DSAPublicKeySpec ks = new DSAPublicKeySpec(y, - params.getP(), - params.getQ(), - params.getG()); - currPubKey = kf.generatePublic(ks); - } catch (GeneralSecurityException e) { - throw new CertPathValidatorException("Unable to generate " + + try { + BigInteger y = ((DSAPublicKey)currPubKey).getY(); + KeyFactory kf = KeyFactory.getInstance("DSA"); + DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(), + params.getQ(), params.getG()); + currPubKey = kf.generatePublic(ks); + } catch (GeneralSecurityException e) { + throw new CertPathValidatorException("Unable to generate " + "key with inherited parameters: " + e.getMessage(), e); - } } } // reset the previous public key prevPubKey = currPubKey; - - // check the extended key usage, ignore the check now - // List extendedKeyUsages = x509Cert.getExtendedKeyUsage(); - - // DO NOT remove any unresolved critical extensions } /** @@ -456,8 +430,10 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { * * @param key the public key to verify the CRL signature * @param crl the target CRL + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - static void check(PublicKey key, X509CRL crl) + static void check(PublicKey key, X509CRL crl, String variant) throws CertPathValidatorException { X509CRLImpl x509CRLImpl = null; @@ -468,7 +444,7 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { } AlgorithmId algorithmId = x509CRLImpl.getSigAlgId(); - check(key, algorithmId); + check(key, algorithmId, variant); } /** @@ -476,20 +452,16 @@ public final class AlgorithmChecker extends PKIXCertPathChecker { * * @param key the public key to verify the CRL signature * @param algorithmId signature algorithm Algorithm ID + * @param variant is the Validator variants of the operation. A null value + * passed will set it to Validator.GENERIC. */ - static void check(PublicKey key, AlgorithmId algorithmId) + static void check(PublicKey key, AlgorithmId algorithmId, String variant) throws CertPathValidatorException { String sigAlgName = algorithmId.getName(); AlgorithmParameters sigAlgParams = algorithmId.getParameters(); - if (!certPathDefaultConstraints.permits( - SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed on signature algorithm: " + - sigAlgName + " is disabled", - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } + certPathDefaultConstraints.permits(new ConstraintsParameters( + sigAlgName, sigAlgParams, key, variant)); } - } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java index 95ef350a9d3..0f16c646a9c 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import javax.security.auth.x500.X500Principal; import java.util.*; import sun.security.util.Debug; +import sun.security.validator.Validator; import static sun.security.x509.PKIXExtensions.*; import sun.security.x509.*; @@ -65,6 +66,20 @@ public class DistributionPointFetcher { * Return the X509CRLs matching this selector. The selector must be * an X509CRLSelector with certificateChecking set. */ + public static Collection getCRLs(X509CRLSelector selector, + boolean signFlag, PublicKey prevKey, String provider, + List certStores, boolean[] reasonsMask, + Set trustAnchors, Date validity, String variant) + throws CertStoreException + { + return getCRLs(selector, signFlag, prevKey, null, provider, certStores, + reasonsMask, trustAnchors, validity, variant); + } + /** + * Return the X509CRLs matching this selector. The selector must be + * an X509CRLSelector with certificateChecking set. + */ + // Called by com.sun.deploy.security.RevocationChecker public static Collection getCRLs(X509CRLSelector selector, boolean signFlag, PublicKey prevKey, @@ -76,7 +91,7 @@ public class DistributionPointFetcher { throws CertStoreException { return getCRLs(selector, signFlag, prevKey, null, provider, certStores, - reasonsMask, trustAnchors, validity); + reasonsMask, trustAnchors, validity, Validator.VAR_GENERIC); } /** @@ -91,7 +106,8 @@ public class DistributionPointFetcher { List certStores, boolean[] reasonsMask, Set trustAnchors, - Date validity) + Date validity, + String variant) throws CertStoreException { X509Certificate cert = selector.getCertificateChecking(); @@ -120,7 +136,7 @@ public class DistributionPointFetcher { DistributionPoint point = t.next(); Collection crls = getCRLs(selector, certImpl, point, reasonsMask, signFlag, prevKey, prevCert, provider, - certStores, trustAnchors, validity); + certStores, trustAnchors, validity, variant); results.addAll(crls); } if (debug != null) { @@ -145,7 +161,7 @@ public class DistributionPointFetcher { X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask, boolean signFlag, PublicKey prevKey, X509Certificate prevCert, String provider, List certStores, - Set trustAnchors, Date validity) + Set trustAnchors, Date validity, String variant) throws CertStoreException { // check for full name @@ -208,7 +224,7 @@ public class DistributionPointFetcher { selector.setIssuerNames(null); if (selector.match(crl) && verifyCRL(certImpl, point, crl, reasonsMask, signFlag, prevKey, prevCert, provider, - trustAnchors, certStores, validity)) { + trustAnchors, certStores, validity, variant)) { crls.add(crl); } } catch (IOException | CRLException e) { @@ -316,7 +332,7 @@ public class DistributionPointFetcher { X509CRL crl, boolean[] reasonsMask, boolean signFlag, PublicKey prevKey, X509Certificate prevCert, String provider, Set trustAnchors, List certStores, - Date validity) throws CRLException, IOException { + Date validity, String variant) throws CRLException, IOException { if (debug != null) { debug.println("DistributionPointFetcher.verifyCRL: " + @@ -663,7 +679,7 @@ public class DistributionPointFetcher { // check the crl signature algorithm try { - AlgorithmChecker.check(prevKey, crl); + AlgorithmChecker.check(prevKey, crl, variant); } catch (CertPathValidatorException cpve) { if (debug != null) { debug.println("CRL signature algorithm check failed: " + cpve); diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java index 8753072e9d0..dce73028cd0 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSP.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ import java.util.Map; import sun.security.action.GetIntegerAction; import sun.security.util.Debug; +import sun.security.validator.Validator; import sun.security.x509.AccessDescription; import sun.security.x509.AuthorityInfoAccessExtension; import sun.security.x509.GeneralName; @@ -94,42 +95,6 @@ public final class OCSP { private OCSP() {} - /** - * Obtains the revocation status of a certificate using OCSP using the most - * common defaults. The OCSP responder URI is retrieved from the - * certificate's AIA extension. The OCSP responder certificate is assumed - * to be the issuer's certificate (or issued by the issuer CA). - * - * @param cert the certificate to be checked - * @param issuerCert the issuer certificate - * @return the RevocationStatus - * @throws IOException if there is an exception connecting to or - * communicating with the OCSP responder - * @throws CertPathValidatorException if an exception occurs while - * encoding the OCSP Request or validating the OCSP Response - */ - public static RevocationStatus check(X509Certificate cert, - X509Certificate issuerCert) - throws IOException, CertPathValidatorException { - CertId certId = null; - URI responderURI = null; - try { - X509CertImpl certImpl = X509CertImpl.toImpl(cert); - responderURI = getResponderURI(certImpl); - if (responderURI == null) { - throw new CertPathValidatorException - ("No OCSP Responder URI in certificate"); - } - certId = new CertId(issuerCert, certImpl.getSerialNumberObject()); - } catch (CertificateException | IOException e) { - throw new CertPathValidatorException - ("Exception while encoding OCSPRequest", e); - } - OCSPResponse ocspResponse = check(Collections.singletonList(certId), - responderURI, new OCSPResponse.IssuerInfo(issuerCert), null, null, - Collections.emptyList()); - return (RevocationStatus)ocspResponse.getSingleResponse(certId); - } /** * Obtains the revocation status of a certificate using OCSP. @@ -146,6 +111,8 @@ public final class OCSP { * @throws CertPathValidatorException if an exception occurs while * encoding the OCSP Request or validating the OCSP Response */ + + // Called by com.sun.deploy.security.TrustDecider public static RevocationStatus check(X509Certificate cert, X509Certificate issuerCert, URI responderURI, @@ -154,27 +121,27 @@ public final class OCSP { throws IOException, CertPathValidatorException { return check(cert, issuerCert, responderURI, responderCert, date, - Collections.emptyList()); + Collections.emptyList(), Validator.VAR_GENERIC); } - // Called by com.sun.deploy.security.TrustDecider + public static RevocationStatus check(X509Certificate cert, - X509Certificate issuerCert, - URI responderURI, - X509Certificate responderCert, - Date date, List extensions) + X509Certificate issuerCert, URI responderURI, + X509Certificate responderCert, Date date, List extensions, + String variant) throws IOException, CertPathValidatorException { - return check(cert, responderURI, null, issuerCert, responderCert, date, extensions); + return check(cert, responderURI, null, issuerCert, responderCert, date, + extensions, variant); } public static RevocationStatus check(X509Certificate cert, URI responderURI, TrustAnchor anchor, X509Certificate issuerCert, X509Certificate responderCert, Date date, - List extensions) + List extensions, String variant) throws IOException, CertPathValidatorException { - CertId certId = null; + CertId certId; try { X509CertImpl certImpl = X509CertImpl.toImpl(cert); certId = new CertId(issuerCert, certImpl.getSerialNumberObject()); @@ -184,7 +151,7 @@ public final class OCSP { } OCSPResponse ocspResponse = check(Collections.singletonList(certId), responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert), - responderCert, date, extensions); + responderCert, date, extensions, variant); return (RevocationStatus) ocspResponse.getSingleResponse(certId); } @@ -206,10 +173,10 @@ public final class OCSP { * @throws CertPathValidatorException if an exception occurs while * encoding the OCSP Request or validating the OCSP Response */ - static OCSPResponse check(List certIds, URI responderURI, + static OCSPResponse check(List certIds, URI responderURI, OCSPResponse.IssuerInfo issuerInfo, X509Certificate responderCert, Date date, - List extensions) + List extensions, String variant) throws IOException, CertPathValidatorException { byte[] nonce = null; @@ -226,7 +193,7 @@ public final class OCSP { // verify the response ocspResponse.verify(certIds, issuerInfo, responderCert, date, - nonce); + nonce, variant); } catch (IOException ioe) { throw new CertPathValidatorException( "Unable to determine revocation status due to network error", diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java index d1770da153a..11f1b0996db 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/OCSPResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import javax.security.auth.x500.X500Principal; @@ -375,7 +374,8 @@ public final class OCSPResponse { } void verify(List certIds, IssuerInfo issuerInfo, - X509Certificate responderCert, Date date, byte[] nonce) + X509Certificate responderCert, Date date, byte[] nonce, + String variant) throws CertPathValidatorException { switch (responseStatus) { @@ -508,7 +508,8 @@ public final class OCSPResponse { // Check algorithm constraints specified in security property // "jdk.certpath.disabledAlgorithms". AlgorithmChecker algChecker = - new AlgorithmChecker(issuerInfo.getAnchor(), date); + new AlgorithmChecker(issuerInfo.getAnchor(), date, + variant); algChecker.init(false); algChecker.check(signerCert, Collections.emptySet()); @@ -568,7 +569,7 @@ public final class OCSPResponse { if (signerCert != null) { // Check algorithm constraints specified in security property // "jdk.certpath.disabledAlgorithms". - AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId); + AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId, variant); if (!verifySignature(signerCert)) { throw new CertPathValidatorException( diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java index f6b0b2ed6f3..8a177c04fc1 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ class PKIX { private Set anchors; private List certs; private Timestamp timestamp; + private String variant; ValidatorParams(CertPath cp, PKIXParameters params) throws InvalidAlgorithmParameterException @@ -102,8 +103,9 @@ class PKIX { ValidatorParams(PKIXParameters params) throws InvalidAlgorithmParameterException { - if (params instanceof PKIXTimestampParameters) { - timestamp = ((PKIXTimestampParameters) params).getTimestamp(); + if (params instanceof PKIXExtendedParameters) { + timestamp = ((PKIXExtendedParameters) params).getTimestamp(); + variant = ((PKIXExtendedParameters) params).getVariant(); } this.anchors = params.getTrustAnchors(); @@ -199,6 +201,10 @@ class PKIX { Timestamp timestamp() { return timestamp; } + + String variant() { + return variant; + } } static class BuilderParams extends ValidatorParams { diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java index ac12fab75ab..b8e20e832f1 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,9 +173,10 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi { // add standard checkers that we will be using certPathCheckers.add(untrustedChecker); if (params.timestamp() == null) { - certPathCheckers.add(new AlgorithmChecker(anchor, params.date())); + certPathCheckers.add(new AlgorithmChecker(anchor, params.date(), null)); } else { - certPathCheckers.add(new AlgorithmChecker(params.timestamp())); + certPathCheckers.add(new AlgorithmChecker(null, + params.timestamp(), params.variant())); } certPathCheckers.add(new KeyChecker(certPathLen, params.targetCertConstraints())); diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXTimestampParameters.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java similarity index 91% rename from jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXTimestampParameters.java rename to jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java index 34b497188e0..42c2d1f9c4f 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXTimestampParameters.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,19 +39,23 @@ import java.util.Set; /** * This class is a wrapper for PKIXBuilderParameters so that a Timestamp object - * can be passed alone when PKIXCertPath is checking signed jar files. + * and a string for the variant type, can be passed when doing certpath + * checking. */ -public class PKIXTimestampParameters extends PKIXBuilderParameters { +public class PKIXExtendedParameters extends PKIXBuilderParameters { private final PKIXBuilderParameters p; private Timestamp jarTimestamp; + private final String variant; - public PKIXTimestampParameters(PKIXBuilderParameters params, - Timestamp timestamp) throws InvalidAlgorithmParameterException { + public PKIXExtendedParameters(PKIXBuilderParameters params, + Timestamp timestamp, String variant) + throws InvalidAlgorithmParameterException { super(params.getTrustAnchors(), null); p = params; jarTimestamp = timestamp; + this.variant = variant; } public Timestamp getTimestamp() { @@ -61,6 +65,10 @@ public class PKIXTimestampParameters extends PKIXBuilderParameters { jarTimestamp = t; } + public String getVariant() { + return variant; + } + @Override public void setDate(Date d) { p.setDate(d); diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java index 5fba1666119..9b443a733dd 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -579,7 +579,7 @@ class RevocationChecker extends PKIXRevocationChecker { approvedCRLs.addAll(DistributionPointFetcher.getCRLs( sel, signFlag, prevKey, prevCert, params.sigProvider(), certStores, - reasonsMask, anchors, null)); + reasonsMask, anchors, null, params.variant())); } } catch (CertStoreException e) { if (e instanceof CertStoreTypeException) { @@ -727,7 +727,7 @@ class RevocationChecker extends PKIXRevocationChecker { } } response.verify(Collections.singletonList(certId), issuerInfo, - responderCert, params.date(), nonce); + responderCert, params.date(), nonce, params.variant()); } else { URI responderURI = (this.responderURI != null) @@ -741,7 +741,7 @@ class RevocationChecker extends PKIXRevocationChecker { response = OCSP.check(Collections.singletonList(certId), responderURI, issuerInfo, responderCert, null, - ocspExtensions); + ocspExtensions, params.variant()); } } catch (IOException e) { throw new CertPathValidatorException( @@ -853,7 +853,7 @@ class RevocationChecker extends PKIXRevocationChecker { if (DistributionPointFetcher.verifyCRL( certImpl, point, crl, reasonsMask, signFlag, prevKey, null, params.sigProvider(), anchors, - certStores, params.date())) + certStores, params.date(), params.variant())) { results.add(crl); } diff --git a/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java b/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java index c0cc98a7a36..11d8a067329 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -344,7 +344,7 @@ public final class SunCertPathBuilder extends CertPathBuilderSpi { // add the algorithm checker checkers.add(new AlgorithmChecker(builder.trustAnchor, - buildParams.date())); + buildParams.date(), null)); BasicChecker basicChecker = null; if (nextState.keyParamsNeeded()) { diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java b/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java index d4f2848c973..c91b25e72ef 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,9 @@ import sun.security.action.GetPropertyAction; final class EllipticCurvesExtension extends HelloExtension { + /* Class and subclass dynamic debugging support */ + private static final Debug debug = Debug.getInstance("ssl"); + private static final int ARBITRARY_PRIME = 0xff01; private static final int ARBITRARY_CHAR2 = 0xff02; @@ -159,6 +162,11 @@ final class EllipticCurvesExtension extends HelloExtension { } // ignore unknown curves } } + if (idList.isEmpty() && JsseJce.isEcAvailable()) { + throw new IllegalArgumentException( + "System property jdk.tls.namedGroups(" + property + ") " + + "contains no supported elliptic curves"); + } } else { // default curves int[] ids; if (requireFips) { @@ -183,16 +191,17 @@ final class EllipticCurvesExtension extends HelloExtension { } } - if (idList.isEmpty()) { - throw new IllegalArgumentException( - "System property jdk.tls.namedGroups(" + property + ") " + - "contains no supported elliptic curves"); - } else { - supportedCurveIds = new int[idList.size()]; - int i = 0; - for (Integer id : idList) { - supportedCurveIds[i++] = id; - } + if (debug != null && idList.isEmpty()) { + Debug.log( + "Initialized [jdk.tls.namedGroups|default] list contains " + + "no available elliptic curves. " + + (property != null ? "(" + property + ")" : "[Default]")); + } + + supportedCurveIds = new int[idList.size()]; + int i = 0; + for (Integer id : idList) { + supportedCurveIds[i++] = id; } } diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index 46ae8d5281e..4f0a95ff80b 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. * 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,6 +37,7 @@ import javax.net.ssl.*; import sun.security.provider.certpath.AlgorithmChecker; import sun.security.action.GetPropertyAction; +import sun.security.validator.Validator; public abstract class SSLContextImpl extends SSLContextSpi { @@ -1436,7 +1437,7 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager constraints = new SSLAlgorithmConstraints(sslSocket, true); } - checkAlgorithmConstraints(chain, constraints); + checkAlgorithmConstraints(chain, constraints, isClient); } } @@ -1478,12 +1479,12 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager constraints = new SSLAlgorithmConstraints(engine, true); } - checkAlgorithmConstraints(chain, constraints); + checkAlgorithmConstraints(chain, constraints, isClient); } } private void checkAlgorithmConstraints(X509Certificate[] chain, - AlgorithmConstraints constraints) throws CertificateException { + AlgorithmConstraints constraints, boolean isClient) throws CertificateException { try { // Does the certificate chain end with a trusted certificate? @@ -1501,7 +1502,9 @@ final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager // A forward checker, need to check from trust to target if (checkedLength >= 0) { - AlgorithmChecker checker = new AlgorithmChecker(constraints); + AlgorithmChecker checker = + new AlgorithmChecker(constraints, null, + (isClient ? Validator.VAR_TLS_CLIENT : Validator.VAR_TLS_SERVER)); checker.init(false); for (int i = checkedLength; i >= 0; i--) { Certificate cert = chain[i]; diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java index b6ed37cc5a3..954b90d15dd 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java @@ -39,6 +39,7 @@ import java.security.cert.Certificate; import javax.net.ssl.*; import sun.security.provider.certpath.AlgorithmChecker; +import sun.security.validator.Validator; /** * The new X509 key manager implementation. The main differences to the @@ -661,6 +662,15 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager return CheckResult.OK; } + + public String getValidator() { + if (this == CLIENT) { + return Validator.VAR_TLS_CLIENT; + } else if (this == SERVER) { + return Validator.VAR_TLS_SERVER; + } + return Validator.VAR_GENERIC; + } } // enum for the result of the extension check @@ -774,7 +784,8 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager // check the algorithm constraints if (constraints != null && - !conformsToAlgorithmConstraints(constraints, chain)) { + !conformsToAlgorithmConstraints(constraints, chain, + checkType.getValidator())) { if (useDebug) { debug.println("Ignoring alias " + alias + @@ -811,9 +822,10 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager } private static boolean conformsToAlgorithmConstraints( - AlgorithmConstraints constraints, Certificate[] chain) { + AlgorithmConstraints constraints, Certificate[] chain, + String variant) { - AlgorithmChecker checker = new AlgorithmChecker(constraints); + AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant); try { checker.init(false); } catch (CertPathValidatorException cpve) { diff --git a/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java b/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java deleted file mode 100644 index 23880f7c6aa..00000000000 --- a/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.security.util; - -import java.security.Timestamp; -import java.security.cert.X509Certificate; -import java.util.Date; - -/** - * This class is a wrapper for keeping state and passing objects between PKIX, - * AlgorithmChecker, and DisabledAlgorithmConstraints. - */ -public class CertConstraintParameters { - // A certificate being passed to check against constraints. - private final X509Certificate cert; - // This is true if the trust anchor in the certificate chain matches a cert - // in AnchorCertificates - private final boolean trustedMatch; - // PKIXParameter date - private final Date pkixDate; - // Timestamp of the signed JAR file - private final Timestamp jarTimestamp; - - public CertConstraintParameters(X509Certificate c, boolean match, - Date pkixdate, Timestamp jarTime) { - cert = c; - trustedMatch = match; - pkixDate = pkixdate; - jarTimestamp = jarTime; - } - - public CertConstraintParameters(X509Certificate c) { - this(c, false, null, null); - } - - // Returns if the trust anchor has a match if anchor checking is enabled. - public boolean isTrustedMatch() { - return trustedMatch; - } - - public X509Certificate getCertificate() { - return cert; - } - - public Date getPKIXParamDate() { - return pkixDate; - } - - public Timestamp getJARTimestamp() { - return jarTimestamp; - } - -} diff --git a/jdk/src/java.base/share/classes/sun/security/util/ConstraintsParameters.java b/jdk/src/java.base/share/classes/sun/security/util/ConstraintsParameters.java new file mode 100644 index 00000000000..84318654557 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/security/util/ConstraintsParameters.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +import sun.security.validator.Validator; + +import java.security.AlgorithmParameters; +import java.security.Key; +import java.security.Timestamp; +import java.security.cert.X509Certificate; +import java.util.Date; + +/** + * This class contains parameters for checking against constraints that extend + * past the publicly available parameters in java.security.AlgorithmConstraints. + + * This is currently on passed between between PKIX, AlgorithmChecker, + * and DisabledAlgorithmConstraints. + */ +public class ConstraintsParameters { + /* + * The below 3 values are used the same as the permit() methods + * published in java.security.AlgorithmConstraints. + */ + // Algorithm string to be checked against constraints + private final String algorithm; + // AlgorithmParameters to the algorithm being checked + private final AlgorithmParameters algParams; + // Public Key being checked against constraints + private final Key publicKey; + + /* + * New values that are checked against constraints that the current public + * API does not support. + */ + // A certificate being passed to check against constraints. + private final X509Certificate cert; + // This is true if the trust anchor in the certificate chain matches a cert + // in AnchorCertificates + private final boolean trustedMatch; + // PKIXParameter date + private final Date pkixDate; + // Timestamp of the signed JAR file + private final Timestamp jarTimestamp; + private final String variant; + + public ConstraintsParameters(X509Certificate c, boolean match, + Date pkixdate, Timestamp jarTime, String variant) { + cert = c; + trustedMatch = match; + pkixDate = pkixdate; + jarTimestamp = jarTime; + this.variant = (variant == null ? Validator.VAR_GENERIC : variant); + algorithm = null; + algParams = null; + publicKey = null; + } + + public ConstraintsParameters(String algorithm, AlgorithmParameters params, + Key key, String variant) { + this.algorithm = algorithm; + algParams = params; + this.publicKey = key; + cert = null; + trustedMatch = false; + pkixDate = null; + jarTimestamp = null; + this.variant = (variant == null ? Validator.VAR_GENERIC : variant); + } + + + public ConstraintsParameters(X509Certificate c) { + this(c, false, null, null, + Validator.VAR_GENERIC); + } + + public ConstraintsParameters(Timestamp jarTime) { + this(null, false, null, jarTime, Validator.VAR_GENERIC); + } + + public String getAlgorithm() { + return algorithm; + } + + public AlgorithmParameters getAlgParams() { + return algParams; + } + + public Key getPublicKey() { + return publicKey; + } + // Returns if the trust anchor has a match if anchor checking is enabled. + public boolean isTrustedMatch() { + return trustedMatch; + } + + public X509Certificate getCertificate() { + return cert; + } + + public Date getPKIXParamDate() { + return pkixDate; + } + + public Timestamp getJARTimestamp() { + return jarTimestamp; + } + + public String getVariant() { + return variant; + } +} diff --git a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java index 73914fe30ae..a8b4a6f0a40 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java +++ b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.security.util; +import sun.security.validator.Validator; + import java.security.CryptoPrimitive; import java.security.AlgorithmParameters; import java.security.Key; @@ -32,10 +34,12 @@ import java.security.cert.CertPathValidatorException; import java.security.cert.CertPathValidatorException.BasicReason; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -100,12 +104,6 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { @Override public final boolean permits(Set primitives, String algorithm, AlgorithmParameters parameters) { - - if (primitives == null || primitives.isEmpty()) { - throw new IllegalArgumentException( - "No cryptographic primitive specified"); - } - return checkAlgorithm(disabledAlgorithms, algorithm, decomposer); } @@ -133,6 +131,18 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { return checkConstraints(primitives, algorithm, key, parameters); } + public final void permits(ConstraintsParameters cp) + throws CertPathValidatorException { + permits(cp.getAlgorithm(), cp); + } + + public final void permits(String algorithm, Key key, + AlgorithmParameters params, String variant) + throws CertPathValidatorException { + permits(algorithm, new ConstraintsParameters(algorithm, params, key, + (variant == null) ? Validator.VAR_GENERIC : variant)); + } + /* * Check if a x509Certificate object is permitted. Check if all * algorithms are allowed, certificate constraints, and the @@ -140,18 +150,10 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { * * Uses new style permit() which throws exceptions. */ - public final void permits(Set primitives, - CertConstraintParameters cp) throws CertPathValidatorException { - checkConstraints(primitives, cp); - } - /* - * Check if Certificate object is within the constraints. - * Uses new style permit() which throws exceptions. - */ - public final void permits(Set primitives, - X509Certificate cert) throws CertPathValidatorException { - checkConstraints(primitives, new CertConstraintParameters(cert)); + public final void permits(String algorithm, ConstraintsParameters cp) + throws CertPathValidatorException { + algorithmConstraints.permits(algorithm, cp); } // Check if a string is contained inside the property @@ -174,7 +176,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { throw new IllegalArgumentException("The key cannot be null"); } - // check the signature algorithm + // check the signature algorithm with parameters if (algorithm != null && algorithm.length() != 0) { if (!permits(primitives, algorithm, parameters)) { return false; @@ -190,36 +192,6 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { return algorithmConstraints.permits(key); } - /* - * Check algorithm constraints with Certificate - * Uses new style permit() which throws exceptions. - */ - private void checkConstraints(Set primitives, - CertConstraintParameters cp) throws CertPathValidatorException { - - X509Certificate cert = cp.getCertificate(); - String algorithm = cert.getSigAlgName(); - - // Check signature algorithm is not disabled - if (!permits(primitives, algorithm, null)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed on disabled "+ - "signature algorithm: " + algorithm, - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } - - // Check key algorithm is not disabled - if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) { - throw new CertPathValidatorException( - "Algorithm constraints check failed on disabled "+ - "public key algorithm: " + algorithm, - null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); - } - - // Check the certificate and key constraints - algorithmConstraints.permits(cp); - - } /** * Key and Certificate Constraints @@ -234,13 +206,13 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { * 'true' means the operation is allowed. * 'false' means it failed the constraints and is disallowed. * - * When passing CertConstraintParameters through permit(), an exception + * When passing ConstraintsParameters through permit(), an exception * will be thrown on a failure to better identify why the operation was * disallowed. */ private static class Constraints { - private Map> constraintsMap = new HashMap<>(); + private Map> constraintsMap = new HashMap<>(); private static class Holder { private static final Pattern DENY_AFTER_PATTERN = Pattern.compile( @@ -260,23 +232,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { // Check if constraint is a complete disabling of an // algorithm or has conditions. - String algorithm; - String policy; int space = constraintEntry.indexOf(' '); - if (space > 0) { - algorithm = AlgorithmDecomposer.hashName( - constraintEntry.substring(0, space). - toUpperCase(Locale.ENGLISH)); - policy = constraintEntry.substring(space + 1); - } else { - algorithm = constraintEntry.toUpperCase(Locale.ENGLISH); - if (!constraintsMap.containsKey(algorithm)) { - constraintsMap.putIfAbsent(algorithm, - new HashSet<>()); - } + String algorithm = AlgorithmDecomposer.hashName( + ((space > 0 ? constraintEntry.substring(0, space) : + constraintEntry). + toUpperCase(Locale.ENGLISH))); + List constraintList = + constraintsMap.getOrDefault(algorithm, + new ArrayList<>(1)); + constraintsMap.putIfAbsent(algorithm, constraintList); + if (space <= 0) { + constraintList.add(new DisabledConstraint(algorithm)); continue; } + String policy = constraintEntry.substring(space + 1); + // Convert constraint conditions into Constraint classes Constraint c, lastConstraint = null; // Allow only one jdkCA entry per constraint entry @@ -315,7 +286,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { c = new jdkCAConstraint(algorithm); jdkCALimit = true; - } else if(entry.startsWith("denyAfter") && + } else if (entry.startsWith("denyAfter") && (matcher = Holder.DENY_AFTER_PATTERN.matcher(entry)) .matches()) { if (debug != null) { @@ -332,6 +303,12 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { c = new DenyAfterConstraint(algorithm, year, month, day); denyAfterLimit = true; + } else if (entry.startsWith("usage")) { + String s[] = (entry.substring(5)).trim().split(" "); + c = new UsageConstraint(algorithm, s); + if (debug != null) { + debug.println("Constraints usage length is " + s.length); + } } else { throw new IllegalArgumentException("Error in security" + " property. Constraint unknown: " + entry); @@ -340,11 +317,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { // Link multiple conditions for a single constraint // into a linked list. if (lastConstraint == null) { - if (!constraintsMap.containsKey(algorithm)) { - constraintsMap.putIfAbsent(algorithm, - new HashSet<>()); - } - constraintsMap.get(algorithm).add(c); + constraintList.add(c); } else { lastConstraint.nextConstraint = c; } @@ -354,17 +327,17 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } // Get applicable constraints based off the signature algorithm - private Set getConstraints(String algorithm) { + private List getConstraints(String algorithm) { return constraintsMap.get(algorithm); } // Check if KeySizeConstraints permit the specified key public boolean permits(Key key) { - Set set = getConstraints(key.getAlgorithm()); - if (set == null) { + List list = getConstraints(key.getAlgorithm()); + if (list == null) { return true; } - for (Constraint constraint : set) { + for (Constraint constraint : list) { if (!constraint.permits(key)) { if (debug != null) { debug.println("keySizeConstraint: failed key " + @@ -377,31 +350,35 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } // Check if constraints permit this cert. - public void permits(CertConstraintParameters cp) + public void permits(String algorithm, ConstraintsParameters cp) throws CertPathValidatorException { X509Certificate cert = cp.getCertificate(); if (debug != null) { - debug.println("Constraints.permits(): " + cert.getSigAlgName()); + debug.println("Constraints.permits(): " + algorithm + + " Variant: " + cp.getVariant()); } // Get all signature algorithms to check for constraints - Set algorithms = - AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName()); - if (algorithms == null || algorithms.isEmpty()) { - return; + Set algorithms = new HashSet<>(); + if (algorithm != null) { + algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm)); } - // Attempt to add the public key algorithm to the set - algorithms.add(cert.getPublicKey().getAlgorithm()); - + // Attempt to add the public key algorithm if cert provided + if (cert != null) { + algorithms.add(cert.getPublicKey().getAlgorithm()); + } + if (cp.getPublicKey() != null) { + algorithms.add(cp.getPublicKey().getAlgorithm()); + } // Check all applicable constraints - for (String algorithm : algorithms) { - Set set = getConstraints(algorithm); - if (set == null) { + for (String alg : algorithms) { + List list = getConstraints(alg); + if (list == null) { continue; } - for (Constraint constraint : set) { + for (Constraint constraint : list) { constraint.permits(cp); } } @@ -467,17 +444,17 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { /** * Check if an algorithm constraint is permitted with a given - * CertConstraintParameters. + * ConstraintsParameters. * * If the check inside of {@code permits()} fails, it must call - * {@code next()} with the same {@code CertConstraintParameters} + * {@code next()} with the same {@code ConstraintsParameters} * parameter passed if multiple constraints need to be checked. * * @param cp CertConstraintParameter containing certificate info * @throws CertPathValidatorException if constraint disallows. * */ - public abstract void permits(CertConstraintParameters cp) + public abstract void permits(ConstraintsParameters cp) throws CertPathValidatorException; /** @@ -491,12 +468,12 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { * were disallowed, the last constraint will throw * {@code CertPathValidatorException}. * - * @param cp CertConstraintParameters + * @param cp ConstraintsParameters * @return 'true' if constraint allows the operation, 'false' if * we are at the end of the constraint list or, * {@code nextConstraint} is null. */ - boolean next(CertConstraintParameters cp) + boolean next(ConstraintsParameters cp) throws CertPathValidatorException { if (nextConstraint != null) { nextConstraint.permits(cp); @@ -525,6 +502,14 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } return false; } + + String extendedMsg(ConstraintsParameters cp) { + return (cp.getCertificate() == null ? "." : + " used with certificate: " + + cp.getCertificate().getSubjectX500Principal() + + (cp.getVariant() != Validator.VAR_GENERIC ? + ". Usage was " + cp.getVariant() : ".")); + } } /* @@ -537,11 +522,11 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } /* - * Check if CertConstraintParameters has a trusted match, if it does + * Check if ConstraintsParameters has a trusted match, if it does * call next() for any following constraints. If it does not, exit * as this constraint(s) does not restrict the operation. */ - public void permits(CertConstraintParameters cp) + public void permits(ConstraintsParameters cp) throws CertPathValidatorException { if (debug != null) { debug.println("jdkCAConstraints.permits(): " + algorithm); @@ -554,8 +539,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } throw new CertPathValidatorException( "Algorithm constraints check failed on certificate " + - "anchor limits. " + algorithm + " used with " + - cp.getCertificate().getSubjectX500Principal(), + "anchor limits. " + algorithm + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } @@ -615,7 +599,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { * constraints. Throw an exception if this is the last constraint. */ @Override - public void permits(CertConstraintParameters cp) + public void permits(ConstraintsParameters cp) throws CertPathValidatorException { Date currentDate; String errmsg; @@ -628,7 +612,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { errmsg = "PKIXParameter date: "; } else { currentDate = new Date(); - errmsg = "Certificate date: "; + errmsg = "Current date: "; } if (!denyAfterDate.after(currentDate)) { @@ -637,9 +621,9 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } throw new CertPathValidatorException( "denyAfter constraint check failed: " + algorithm + - " used with Constraint date: " + - dateFormat.format(denyAfterDate) + "; " - + errmsg + dateFormat.format(currentDate), + " used with Constraint date: " + + dateFormat.format(denyAfterDate) + "; " + errmsg + + dateFormat.format(currentDate) + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } @@ -660,6 +644,48 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { } } + /* + * The usage constraint is for the "usage" keyword. It checks against the + * variant value in ConstraintsParameters. + */ + private static class UsageConstraint extends Constraint { + String[] usages; + + UsageConstraint(String algorithm, String[] usages) { + this.algorithm = algorithm; + this.usages = usages; + } + + public void permits(ConstraintsParameters cp) + throws CertPathValidatorException { + for (String usage : usages) { + + String v = null; + if (usage.compareToIgnoreCase("TLSServer") == 0) { + v = Validator.VAR_TLS_SERVER; + } else if (usage.compareToIgnoreCase("TLSClient") == 0) { + v = Validator.VAR_TLS_CLIENT; + } else if (usage.compareToIgnoreCase("SignedJAR") == 0) { + v = Validator.VAR_PLUGIN_CODE_SIGNING; + } + + if (debug != null) { + debug.println("Checking if usage constraint " + v + + " matches " + cp.getVariant()); + } + if (cp.getVariant().compareTo(v) == 0) { + if (next(cp)) { + return; + } + throw new CertPathValidatorException("Usage constraint " + + usage + " check failed: " + algorithm + + extendedMsg(cp), + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } + } + } + } + /* * This class contains constraints dealing with the key size * support limits per algorithm. e.g. "keySize <= 1024" @@ -713,17 +739,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { * constraint Any permitted constraint will exit the linked list * to allow the operation. */ - public void permits(CertConstraintParameters cp) + public void permits(ConstraintsParameters cp) throws CertPathValidatorException { - if (!permitsImpl(cp.getCertificate().getPublicKey())) { + Key key = null; + if (cp.getPublicKey() != null) { + key = cp.getPublicKey(); + } else if (cp.getCertificate() != null) { + key = cp.getCertificate().getPublicKey(); + } + if (key != null && !permitsImpl(key)) { if (nextConstraint != null) { nextConstraint.permits(cp); return; } throw new CertPathValidatorException( "Algorithm constraints check failed on keysize limits. " - + algorithm + " " + size + "bit key used with " - + cp.getCertificate().getSubjectX500Principal(), + + algorithm + " " + size + "bit key" + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } @@ -762,5 +793,26 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { return true; } } + + /* + * This constraint is used for the complete disabling of the algorithm. + */ + private static class DisabledConstraint extends Constraint { + DisabledConstraint(String algo) { + algorithm = algo; + } + + public void permits(ConstraintsParameters cp) + throws CertPathValidatorException { + throw new CertPathValidatorException( + "Algorithm constraints check failed on disabled " + + "algorithm: " + algorithm + extendedMsg(cp), + null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); + } + + public boolean permits(Key key) { + return false; + } + } } diff --git a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index f8022c5ca94..2fe1c7ee91e 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,25 +28,23 @@ package sun.security.util; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.CodeSigner; -import java.security.CryptoPrimitive; +import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; +import java.security.Timestamp; import java.security.cert.CertPath; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.util.ArrayList; import java.util.Base64; -import java.util.Collections; -import java.util.EnumSet; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Set; import java.util.jar.Attributes; import java.util.jar.JarException; import java.util.jar.JarFile; @@ -61,9 +59,6 @@ public class SignatureFileVerifier { /* Are we debugging ? */ private static final Debug debug = Debug.getInstance("jar"); - private static final Set DIGEST_PRIMITIVE_SET = - Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST)); - private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK = new DisabledAlgorithmConstraints( DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS); @@ -97,6 +92,14 @@ public class SignatureFileVerifier { /* for generating certpath objects */ private CertificateFactory certificateFactory = null; + /** Algorithms that have been checked if they are weak. */ + private Map permittedAlgs= new HashMap<>(); + + /** TSA timestamp of signed jar. The newest timestamp is used. If there + * was no TSA timestamp used when signed, current time is used ("null"). + */ + private Timestamp timestamp = null; + /** * Create the named SignatureFileVerifier. * @@ -222,15 +225,8 @@ public class SignatureFileVerifier { /** get digest from cache */ - private MessageDigest getDigest(String algorithm) throws SignatureException { - // check that algorithm is not restricted - if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, algorithm, null)) { - SignatureException e = - new SignatureException("SignatureFile check failed. " + - "Disabled algorithm used: " + algorithm); - throw e; - } - + private MessageDigest getDigest(String algorithm) + throws SignatureException { if (createdDigests == null) createdDigests = new HashMap<>(); @@ -302,6 +298,27 @@ public class SignatureFileVerifier { if (newSigners == null) return; + /* + * Look for the latest timestamp in the signature block. If an entry + * has no timestamp, use current time (aka null). + */ + for (CodeSigner s: newSigners) { + if (debug != null) { + debug.println("Gathering timestamp for: " + s.toString()); + } + if (s.getTimestamp() == null) { + timestamp = null; + break; + } else if (timestamp == null) { + timestamp = s.getTimestamp(); + } else { + if (timestamp.getTimestamp().before( + s.getTimestamp().getTimestamp())) { + timestamp = s.getTimestamp(); + } + } + } + Iterator> entries = sf.getEntries().entrySet().iterator(); @@ -344,6 +361,68 @@ public class SignatureFileVerifier { updateSigners(newSigners, signers, JarFile.MANIFEST_NAME); } + /** + * Check if algorithm is permitted using the permittedAlgs Map. + * If the algorithm is not in the map, check against disabled algorithms and + * store the result. If the algorithm is in the map use that result. + * False is returned for weak algorithm, true for good algorithms. + */ + boolean permittedCheck(String key, String algorithm) { + Boolean permitted = permittedAlgs.get(algorithm); + if (permitted == null) { + try { + JAR_DISABLED_CHECK.permits(algorithm, + new ConstraintsParameters(timestamp)); + } catch(GeneralSecurityException e) { + permittedAlgs.put(algorithm, Boolean.FALSE); + permittedAlgs.put(key.toUpperCase(), Boolean.FALSE); + if (debug != null) { + if (e.getMessage() != null) { + debug.println(key + ": " + e.getMessage()); + } else { + debug.println(key + ": " + algorithm + + " was disabled, no exception msg given."); + e.printStackTrace(); + } + } + return false; + } + + permittedAlgs.put(algorithm, Boolean.TRUE); + return true; + } + + // Algorithm has already been checked, return the value from map. + return permitted.booleanValue(); + } + + /** + * With a given header (*-DIGEST*), return a string that lists all the + * algorithms associated with the header. + * If there are none, return "Unknown Algorithm". + */ + String getWeakAlgorithms(String header) { + String w = ""; + try { + for (String key : permittedAlgs.keySet()) { + if (key.endsWith(header)) { + w += key.substring(0, key.length() - header.length()) + " "; + } + } + } catch (RuntimeException e) { + w = "Unknown Algorithm(s). Error processing " + header + ". " + + e.getMessage(); + } + + // This means we have an error in finding weak algorithms, run in + // debug mode to see permittedAlgs map's values. + if (w.length() == 0) { + return "Unknown Algorithm(s)"; + } + + return w; + } + /** * See if the whole manifest was signed. */ @@ -354,6 +433,7 @@ public class SignatureFileVerifier { { Attributes mattr = sf.getMainAttributes(); boolean manifestSigned = false; + boolean weakAlgs = true; // go through all the attributes and process *-Digest-Manifest entries for (Map.Entry se : mattr.entrySet()) { @@ -364,6 +444,15 @@ public class SignatureFileVerifier { // 16 is length of "-Digest-Manifest" String algorithm = key.substring(0, key.length()-16); + // Check if this algorithm is permitted, skip if false. + if (!permittedCheck(key, algorithm)) { + continue; + } + + // A non-weak algorithm was used, any weak algorithms found do + // not need to be reported. + weakAlgs = false; + manifestDigests.add(key); manifestDigests.add(se.getValue()); MessageDigest digest = getDigest(algorithm); @@ -373,15 +462,14 @@ public class SignatureFileVerifier { Base64.getMimeDecoder().decode((String)se.getValue()); if (debug != null) { - debug.println("Signature File: Manifest digest " + - digest.getAlgorithm()); - debug.println( " sigfile " + toHex(expectedHash)); - debug.println( " computed " + toHex(computedHash)); - debug.println(); + debug.println("Signature File: Manifest digest " + + algorithm); + debug.println( " sigfile " + toHex(expectedHash)); + debug.println( " computed " + toHex(computedHash)); + debug.println(); } - if (MessageDigest.isEqual(computedHash, - expectedHash)) { + if (MessageDigest.isEqual(computedHash, expectedHash)) { manifestSigned = true; } else { //XXX: we will continue and verify each section @@ -389,15 +477,31 @@ public class SignatureFileVerifier { } } } + + if (debug != null) { + debug.println("PermittedAlgs mapping: "); + for (String key : permittedAlgs.keySet()) { + debug.println(key + " : " + + permittedAlgs.get(key).toString()); + } + } + + // If there were only weak algorithms used, throw an exception. + if (weakAlgs) { + String weakAlgorithms = getWeakAlgorithms("-DIGEST-MANIFEST"); + throw new SignatureException("Manifest hash check failed " + + "(DIGEST-MANIFEST). Disabled algorithm(s) used: " + + weakAlgorithms); + } return manifestSigned; } - private boolean verifyManifestMainAttrs(Manifest sf, - ManifestDigester md) + private boolean verifyManifestMainAttrs(Manifest sf, ManifestDigester md) throws IOException, SignatureException { Attributes mattr = sf.getMainAttributes(); boolean attrsVerified = true; + boolean weakAlgs = true; // go through all the attributes and process // digest entries for the manifest main attributes @@ -408,6 +512,15 @@ public class SignatureFileVerifier { String algorithm = key.substring(0, key.length() - ATTR_DIGEST.length()); + // Check if this algorithm is permitted, skip if false. + if (!permittedCheck(key, algorithm)) { + continue; + } + + // A non-weak algorithm was used, any weak algorithms found do + // not need to be reported. + weakAlgs = false; + MessageDigest digest = getDigest(algorithm); if (digest != null) { ManifestDigester.Entry mde = @@ -425,8 +538,7 @@ public class SignatureFileVerifier { debug.println(); } - if (MessageDigest.isEqual(computedHash, - expectedHash)) { + if (MessageDigest.isEqual(computedHash, expectedHash)) { // good } else { // we will *not* continue and verify each section @@ -442,6 +554,23 @@ public class SignatureFileVerifier { } } + if (debug != null) { + debug.println("PermittedAlgs mapping: "); + for (String key : permittedAlgs.keySet()) { + debug.println(key + " : " + + permittedAlgs.get(key).toString()); + } + } + + // If there were only weak algorithms used, throw an exception. + if (weakAlgs) { + String weakAlgorithms = getWeakAlgorithms("-DIGEST-" + + ManifestDigester.MF_MAIN_ATTRS); + throw new SignatureException("Manifest Main Attribute check " + + "failed (DIGEST-" + ManifestDigester.MF_MAIN_ATTRS + + "). " + "Disabled algorithm(s) used: " + weakAlgorithms); + } + // this method returns 'true' if either: // . manifest main attributes were not signed, or // . manifest main attributes were signed and verified @@ -464,6 +593,7 @@ public class SignatureFileVerifier { { boolean oneDigestVerified = false; ManifestDigester.Entry mde = md.get(name,block.isOldStyle()); + boolean weakAlgs = true; if (mde == null) { throw new SecurityException( @@ -471,7 +601,6 @@ public class SignatureFileVerifier { } if (sfAttr != null) { - //sun.security.util.HexDumpEncoder hex = new sun.security.util.HexDumpEncoder(); //hex.encodeBuffer(data, System.out); @@ -483,6 +612,15 @@ public class SignatureFileVerifier { // 7 is length of "-Digest" String algorithm = key.substring(0, key.length()-7); + // Check if this algorithm is permitted, skip if false. + if (!permittedCheck(key, algorithm)) { + continue; + } + + // A non-weak algorithm was used, any weak algorithms found do + // not need to be reported. + weakAlgs = false; + MessageDigest digest = getDigest(algorithm); if (digest != null) { @@ -532,6 +670,23 @@ public class SignatureFileVerifier { } } } + + if (debug != null) { + debug.println("PermittedAlgs mapping: "); + for (String key : permittedAlgs.keySet()) { + debug.println(key + " : " + + permittedAlgs.get(key).toString()); + } + } + + // If there were only weak algorithms used, throw an exception. + if (weakAlgs) { + String weakAlgorithms = getWeakAlgorithms("DIGEST"); + throw new SignatureException("Manifest Main Attribute check " + + "failed (DIGEST). " + "Disabled algorithm(s) used: " + + weakAlgorithms); + } + return oneDigestVerified; } diff --git a/jdk/src/java.base/share/classes/sun/security/validator/PKIXValidator.java b/jdk/src/java.base/share/classes/sun/security/validator/PKIXValidator.java index 8d63ea2b8f5..0a7be5a31e0 100644 --- a/jdk/src/java.base/share/classes/sun/security/validator/PKIXValidator.java +++ b/jdk/src/java.base/share/classes/sun/security/validator/PKIXValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import java.security.cert.*; import javax.security.auth.x500.X500Principal; import sun.security.action.GetBooleanAction; import sun.security.provider.certpath.AlgorithmChecker; -import sun.security.provider.certpath.PKIXTimestampParameters; +import sun.security.provider.certpath.PKIXExtendedParameters; /** * Validator implementation built on the PKIX CertPath API. This @@ -199,9 +199,9 @@ public final class PKIXValidator extends Validator { PKIXBuilderParameters pkixParameters = null; if (parameter instanceof Timestamp && plugin) { try { - pkixParameters = new PKIXTimestampParameters( + pkixParameters = new PKIXExtendedParameters( (PKIXBuilderParameters) parameterTemplate.clone(), - (Timestamp) parameter); + (Timestamp) parameter, variant); } catch (InvalidAlgorithmParameterException e) { // ignore exception } @@ -211,7 +211,8 @@ public final class PKIXValidator extends Validator { // add new algorithm constraints checker if (constraints != null) { - pkixParameters.addCertPathChecker(new AlgorithmChecker(constraints)); + pkixParameters.addCertPathChecker( + new AlgorithmChecker(constraints, null, variant)); } // attach it to the PKIXBuilderParameters. diff --git a/jdk/src/java.base/share/classes/sun/security/validator/SimpleValidator.java b/jdk/src/java.base/share/classes/sun/security/validator/SimpleValidator.java index 58f7a5db419..7b7068fa9e6 100644 --- a/jdk/src/java.base/share/classes/sun/security/validator/SimpleValidator.java +++ b/jdk/src/java.base/share/classes/sun/security/validator/SimpleValidator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -155,12 +155,14 @@ public final class SimpleValidator extends Validator { // create default algorithm constraints checker TrustAnchor anchor = new TrustAnchor(anchorCert, null); - AlgorithmChecker defaultAlgChecker = new AlgorithmChecker(anchor); + AlgorithmChecker defaultAlgChecker = + new AlgorithmChecker(anchor, variant); // create application level algorithm constraints checker AlgorithmChecker appAlgChecker = null; if (constraints != null) { - appAlgChecker = new AlgorithmChecker(anchor, constraints); + appAlgChecker = new AlgorithmChecker(anchor, constraints, null, + variant); } // verify top down, starting at the certificate issued by diff --git a/jdk/src/java.base/share/conf/security/java.security b/jdk/src/java.base/share/conf/security/java.security index 5e778810bb7..e2fde354bd4 100644 --- a/jdk/src/java.base/share/conf/security/java.security +++ b/jdk/src/java.base/share/conf/security/java.security @@ -116,6 +116,13 @@ security.provider.tbd=SunPKCS11 # Example: # jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \ # MessageDigest.SHA-256:SUN, Group.HmacSHA2:SunJCE +# +#ifdef solaris-sparc +# Optional Solaris-SPARC configuration for non-FIPS 140 configurations. +# jdk.security.provider.preferred=AES:SunJCE, SHA1:SUN, Group.SHA2:SUN, \ +# HmacSHA1:SunJCE, Group.HmacSHA2:SunJCE +# +#endif #jdk.security.provider.preferred= @@ -240,6 +247,7 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN # # The default value is an empty string, which is equivalent to # securerandom.drbg.config=Hash_DRBG,SHA-256,128,none +# securerandom.drbg.config= # @@ -262,23 +270,27 @@ policy.provider=sun.security.provider.PolicyFile # The default is to have a single system-wide policy file, # and a policy file in the user's home directory. +# policy.url.1=file:${java.home}/conf/security/java.policy policy.url.2=file:${user.home}/.java.policy # whether or not we expand properties in the policy file # if this is set to false, properties (${...}) will not be expanded in policy # files. +# policy.expandProperties=true # whether or not we allow an extra policy to be passed on the command line # with -Djava.security.policy=somefile. Comment out this line to disable # this feature. +# policy.allowSystemProperty=true # whether or not we look into the IdentityScope for trusted Identities # when encountering a 1.1 signed JAR file. If the identity is found # and is trusted, we grant it AllPermission. Note: the default policy # provider (sun.security.provider.PolicyFile) does not support this property. +# policy.ignoreIdentityScope=false # @@ -360,7 +372,6 @@ ssl.TrustManagerFactory.algorithm=PKIX # For this reason the default caching policy is to maintain these # results for 10 seconds. # -# networkaddress.cache.negative.ttl=10 # @@ -460,8 +471,10 @@ networkaddress.cache.negative.ttl=10 # Example, # krb5.kdc.bad.policy = tryLast # krb5.kdc.bad.policy = tryLess:2,2000 +# krb5.kdc.bad.policy = tryLast +# # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable @@ -481,7 +494,8 @@ krb5.kdc.bad.policy = tryLast # (see below) # # Constraint: -# KeySizeConstraint | CAConstraint | DenyAfterConstraint +# KeySizeConstraint | CAConstraint | DenyAfterConstraint | +# UsageConstraint # # KeySizeConstraint: # keySize Operator KeyLength @@ -498,6 +512,9 @@ krb5.kdc.bad.policy = tryLast # DenyAfterConstraint: # denyAfter YYYY-MM-DD # +# UsageConstraint: +# usage [TLSServer] [TLSClient] [SignedJAR] +# # The "AlgorithmName" is the standard algorithm name of the disabled # algorithm. See "Java Cryptography Architecture Standard Algorithm Name # Documentation" for information about Standard Algorithm Names. Matching @@ -547,6 +564,19 @@ krb5.kdc.bad.policy = tryLast # Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020, # use the following: "RSA keySize == 2048 & denyAfter 2020-02-03" # +# UsageConstraint: +# usage [TLSServer] [TLSClient] [SignedJAR] +# This constraint prohibits the specified algorithm for +# a specified usage. This should be used when disabling an algorithm +# for all usages is not practical. 'TLSServer' restricts the algorithm +# in TLS server certificate chains when server authentication is +# performed. 'TLSClient' restricts the algorithm in TLS client +# certificate chains when client authentication is performed. +# 'SignedJAR' constrains use of certificates in signed jar files. +# The usage type follows the keyword and more than one usage type can +# be specified with a whitespace delimiter. +# Example: "SHA1 usage TLSServer TLSClient" +# # When an algorithm must satisfy more than one constraint, it must be # delimited by an ampersand '&'. For example, to restrict certificates in a # chain that terminate at a distribution provided trust anchor and contain @@ -572,35 +602,6 @@ jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & denyAfter 2017-01-01, \ RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224 # -# RMI Registry Serial Filter -# -# The filter pattern uses the same format as jdk.serialFilter. -# This filter can override the builtin filter if additional types need to be -# allowed or rejected from the RMI Registry. -# -# Note: This property is currently used by the JDK Reference implementation. -# It is not guaranteed to be examined and used by other implementations. -# -#sun.rmi.registry.registryFilter=pattern;pattern -# -# RMI Distributed Garbage Collector (DGC) Serial Filter -# -# The filter pattern uses the same format as jdk.serialFilter. -# This filter can override the builtin filter if additional types need to be -# allowed or rejected from the RMI DGC. -# -# Note: This property is currently used by the JDK Reference implementation. -# It is not guaranteed to be examined and used by other implementations. -# -# The builtin DGC filter can approximately be represented as the filter pattern: -# -#sun.rmi.transport.dgcFilter=\ -# java.rmi.server.ObjID;\ -# java.rmi.server.UID;\ -# java.rmi.dgc.VMID;\ -# java.rmi.dgc.Lease;\ -# maxdepth=5;maxarray=10000 - # Algorithm restrictions for signed JAR files # # In some environments, certain algorithms or key lengths may be undesirable @@ -615,17 +616,20 @@ jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & denyAfter 2017-01-01, \ # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: -# AlgorithmName [Constraint] +# AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: -# KeySizeConstraint +# KeySizeConstraint | DenyAfterConstraint # # KeySizeConstraint: # keySize Operator KeyLength # +# DenyAfterConstraint: +# denyAfter YYYY-MM-DD +# # Operator: # <= | < | == | != | >= | > # @@ -636,9 +640,12 @@ jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & denyAfter 2017-01-01, \ # implementation. It is not guaranteed to be examined and used by other # implementations. # +# See "jdk.certpath.disabledAlgorithms" for syntax descriptions. +# jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ DSA keySize < 1024 +# # Algorithm restrictions for Secure Socket Layer/Transport Layer Security # (SSL/TLS/DTLS) processing # @@ -939,3 +946,32 @@ jdk.xml.dsig.secureValidationPolicy=\ # #jdk.serialFilter=pattern;pattern +# +# RMI Registry Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI Registry. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +#sun.rmi.registry.registryFilter=pattern;pattern +# +# RMI Distributed Garbage Collector (DGC) Serial Filter +# +# The filter pattern uses the same format as jdk.serialFilter. +# This filter can override the builtin filter if additional types need to be +# allowed or rejected from the RMI DGC. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# The builtin DGC filter can approximately be represented as the filter pattern: +# +#sun.rmi.transport.dgcFilter=\ +# java.rmi.server.ObjID;\ +# java.rmi.server.UID;\ +# java.rmi.dgc.VMID;\ +# java.rmi.dgc.Lease;\ +# maxdepth=5;maxarray=10000 diff --git a/jdk/src/java.base/share/lib/security/default.policy b/jdk/src/java.base/share/lib/security/default.policy index 7f7ad4ff4b3..36521f38e1d 100644 --- a/jdk/src/java.base/share/lib/security/default.policy +++ b/jdk/src/java.base/share/lib/security/default.policy @@ -102,6 +102,8 @@ grant codeBase "jrt:/java.xml.crypto" { }; grant codeBase "jrt:/java.xml.ws" { + permission java.net.NetPermission + "getProxySelector"; permission java.lang.RuntimePermission "accessClassInPackage.com.sun.org.apache.xml.internal.resolver"; permission java.lang.RuntimePermission @@ -213,3 +215,7 @@ grant { permission java.lang.RuntimePermission "accessClassInPackage.com.sun.java.swing.plaf.*"; permission java.lang.RuntimePermission "accessClassInPackage.com.apple.*"; }; + +grant codeBase "jrt:/jdk.vm.compiler" { + permission java.security.AllPermission; +}; diff --git a/jdk/src/java.base/share/native/launcher/main.c b/jdk/src/java.base/share/native/launcher/main.c index acbff5ff316..8e27a2a2ed9 100644 --- a/jdk/src/java.base/share/native/launcher/main.c +++ b/jdk/src/java.base/share/native/launcher/main.c @@ -130,10 +130,10 @@ main(int argc, char **argv) // Add first arg, which is the app name JLI_List_add(args, JLI_StringDup(argv[0])); - // Append JAVA_OPTIONS - if (JLI_AddArgsFromEnvVar(args, JAVA_OPTIONS)) { + // Append JDK_JAVA_OPTIONS + if (JLI_AddArgsFromEnvVar(args, JDK_JAVA_OPTIONS)) { // JLI_SetTraceLauncher is not called yet - // Show _JAVA_OPTIONS content along with JAVA_OPTIONS to aid diagnosis + // Show _JAVA_OPTIONS content along with JDK_JAVA_OPTIONS to aid diagnosis if (getenv(JLDEBUG_ENV_ENTRY)) { char *tmp = getenv("_JAVA_OPTIONS"); if (NULL != tmp) { diff --git a/jdk/src/java.base/share/native/libjli/args.c b/jdk/src/java.base/share/native/libjli/args.c index d24301c3db9..adbff674bf9 100644 --- a/jdk/src/java.base/share/native/libjli/args.c +++ b/jdk/src/java.base/share/native/libjli/args.c @@ -34,7 +34,7 @@ #define NO_JNI #endif #define JLI_ReportMessage(...) printf(__VA_ARGS__) - #define JAVA_OPTIONS "JAVA_OPTIONS" + #define JDK_JAVA_OPTIONS "JDK_JAVA_OPTIONS" int IsWhiteSpaceOption(const char* name) { return 1; } #else #include "java.h" @@ -429,10 +429,6 @@ int isTerminalOpt(char *arg) { } jboolean JLI_AddArgsFromEnvVar(JLI_List args, const char *var_name) { - -#ifndef ENABLE_JAVA_OPTIONS - return JNI_FALSE; -#else char *env = getenv(var_name); char *p, *arg; char quote; @@ -519,7 +515,6 @@ jboolean JLI_AddArgsFromEnvVar(JLI_List args, const char *var_name) { } return JNI_TRUE; -#endif } #ifdef DEBUG_ARGFILE diff --git a/jdk/src/java.base/share/native/libjli/java.h b/jdk/src/java.base/share/native/libjli/java.h index d035a080d9d..842dcc9cf9d 100644 --- a/jdk/src/java.base/share/native/libjli/java.h +++ b/jdk/src/java.base/share/native/libjli/java.h @@ -71,7 +71,7 @@ #define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE" #define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR" -#define JAVA_OPTIONS "JAVA_OPTIONS" +#define JDK_JAVA_OPTIONS "JDK_JAVA_OPTIONS" /* * Pointers to the needed JNI invocation API, initialized by LoadJavaVM. diff --git a/jdk/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java new file mode 100644 index 00000000000..83fddff2a54 --- /dev/null +++ b/jdk/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.fs; + +import java.nio.file.spi.FileSystemProvider; + +/** + * Creates this platform's default FileSystemProvider. + */ + +public class DefaultFileSystemProvider { + private DefaultFileSystemProvider() { } + + /** + * Returns the default FileSystemProvider. + */ + public static FileSystemProvider create() { + return new SolarisFileSystemProvider(); + } +} diff --git a/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java b/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java deleted file mode 100644 index 42064456453..00000000000 --- a/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.nio.fs; - -import java.nio.file.spi.FileSystemProvider; -import sun.security.action.GetPropertyAction; - -/** - * Creates this platform's default FileSystemProvider. - */ - -public class DefaultFileSystemProvider { - private DefaultFileSystemProvider() { } - - @SuppressWarnings("unchecked") - private static FileSystemProvider createProvider(String cn) { - Class c; - try { - c = (Class)Class.forName(cn); - } catch (ClassNotFoundException x) { - throw new AssertionError(x); - } - try { - @SuppressWarnings("deprecation") - FileSystemProvider result = c.newInstance(); - return result; - } catch (IllegalAccessException | InstantiationException x) { - throw new AssertionError(x); - } - } - - /** - * Returns the default FileSystemProvider. - */ - public static FileSystemProvider create() { - String osname = GetPropertyAction.privilegedGetProperty("os.name"); - if (osname.equals("SunOS")) - return createProvider("sun.nio.fs.SolarisFileSystemProvider"); - if (osname.equals("Linux")) - return createProvider("sun.nio.fs.LinuxFileSystemProvider"); - if (osname.contains("OS X")) - return createProvider("sun.nio.fs.MacOSXFileSystemProvider"); - if (osname.equals("AIX")) - return createProvider("sun.nio.fs.AixFileSystemProvider"); - throw new AssertionError("Platform not recognized"); - } -} diff --git a/jdk/src/java.base/windows/native/libjli/cmdtoargs.c b/jdk/src/java.base/windows/native/libjli/cmdtoargs.c index f984885ed01..955775f9d42 100644 --- a/jdk/src/java.base/windows/native/libjli/cmdtoargs.c +++ b/jdk/src/java.base/windows/native/libjli/cmdtoargs.c @@ -205,9 +205,9 @@ void JLI_CmdToArgs(char* cmdline) { size_t i, cnt; JLI_List envArgs = JLI_List_new(1); - if (JLI_AddArgsFromEnvVar(envArgs, JAVA_OPTIONS)) { + if (JLI_AddArgsFromEnvVar(envArgs, JDK_JAVA_OPTIONS)) { // JLI_SetTraceLauncher is not called yet - // Show _JAVA_OPTIONS content along with JAVA_OPTIONS to aid diagnosis + // Show _JAVA_OPTIONS content along with JDK_JAVA_OPTIONS to aid diagnosis if (getenv(JLDEBUG_ENV_ENTRY)) { char *tmp = getenv("_JAVA_OPTIONS"); if (NULL != tmp) { diff --git a/jdk/src/java.datatransfer/share/classes/module-info.java b/jdk/src/java.datatransfer/share/classes/module-info.java index ea3f9c2a53c..35b7571fb92 100644 --- a/jdk/src/java.datatransfer/share/classes/module-info.java +++ b/jdk/src/java.datatransfer/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines an API for transferring data between and within applications. + * + * @since 9 */ module java.datatransfer { exports java.awt.datatransfer; diff --git a/jdk/src/java.desktop/share/classes/module-info.java b/jdk/src/java.desktop/share/classes/module-info.java index 33ae0832d4d..841618d8216 100644 --- a/jdk/src/java.desktop/share/classes/module-info.java +++ b/jdk/src/java.desktop/share/classes/module-info.java @@ -26,6 +26,8 @@ /** * Defines the AWT and Swing user interface toolkits, plus APIs for * accessibility, audio, imaging, printing, and JavaBeans. + * + * @since 9 */ module java.desktop { requires transitive java.datatransfer; diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java b/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java index 17c5bede590..ab0d540f9c8 100644 --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java @@ -229,6 +229,7 @@ public interface ClassFileTransformer { * or {@code null} if no transform is performed * * @since 9 + * @spec JPMS */ default byte[] transform( Module module, diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java index 97986c2e610..bc4170d3af2 100644 --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java @@ -714,6 +714,7 @@ public interface Instrumentation { * @throws NullPointerException if any of the arguments are {@code null} or * any of the Sets or Maps contains a {@code null} key or value * @since 9 + * @spec JPMS */ void redefineModule(Module module, Set extraReads, diff --git a/jdk/src/java.instrument/share/classes/module-info.java b/jdk/src/java.instrument/share/classes/module-info.java index 27587d2c250..4a7f2199e1d 100644 --- a/jdk/src/java.instrument/share/classes/module-info.java +++ b/jdk/src/java.instrument/share/classes/module-info.java @@ -26,6 +26,8 @@ /** * Defines services that allow agents to * instrument programs running on the JVM. + * + * @since 9 */ module java.instrument { exports java.lang.instrument; diff --git a/jdk/src/java.logging/share/classes/module-info.java b/jdk/src/java.logging/share/classes/module-info.java index 293d3873da1..a8120deeedb 100644 --- a/jdk/src/java.logging/share/classes/module-info.java +++ b/jdk/src/java.logging/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the Java Logging API. + * + * @since 9 */ module java.logging { exports java.util.logging; diff --git a/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java index 7684567c1ca..7c5cd32811f 100644 --- a/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/jdk/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -38,6 +38,7 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamClass; import java.io.Serializable; +import java.lang.module.ModuleDescriptor; import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; @@ -107,6 +108,8 @@ import sun.rmi.server.UnicastRef2; import sun.rmi.transport.LiveRef; import java.io.NotSerializableException; +import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC; + /** *

    A connection to a remote RMI connector. Usually, such * connections are made using {@link @@ -2020,8 +2023,14 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable Module rmiModule = RemoteRef.class.getModule(); String pkg = packageOf(pRefClassName); - assert pkg != null && pkg.length() > 0 && !pkg.equals(packageOf(proxyRefCName)); - Module m = Modules.defineModule(cl, "jdk.remoteref", Collections.singleton(pkg)); + assert pkg != null && pkg.length() > 0 && + !pkg.equals(packageOf(proxyRefCName)); + + ModuleDescriptor descriptor = + ModuleDescriptor.newModule("jdk.remoteref", Set.of(SYNTHETIC)) + .packages(Set.of(pkg)) + .build(); + Module m = Modules.defineModule(cl, descriptor, null); // jdk.remoteref needs to read to java.base and jmxModule Modules.addReads(m, Object.class.getModule()); diff --git a/jdk/src/java.management.rmi/share/classes/module-info.java b/jdk/src/java.management.rmi/share/classes/module-info.java index ae6fc006c99..fca14d540a8 100644 --- a/jdk/src/java.management.rmi/share/classes/module-info.java +++ b/jdk/src/java.management.rmi/share/classes/module-info.java @@ -46,6 +46,7 @@ * and load the appropriate {@code JMXConnectorServerProvider} service * implementation for the given protocol. * + * @since 9 */ module java.management.rmi { diff --git a/jdk/src/java.management/share/classes/module-info.java b/jdk/src/java.management/share/classes/module-info.java index ef7940a10ab..fd8ec495098 100644 --- a/jdk/src/java.management/share/classes/module-info.java +++ b/jdk/src/java.management/share/classes/module-info.java @@ -28,6 +28,8 @@ *

    * The JMX API consists of interfaces for monitoring and management of the * JVM and other components in the Java runtime. + * + * @since 9 */ module java.management { diff --git a/jdk/src/java.naming/share/classes/module-info.java b/jdk/src/java.naming/share/classes/module-info.java index f524a4c0bcd..bd1332a5f7b 100644 --- a/jdk/src/java.naming/share/classes/module-info.java +++ b/jdk/src/java.naming/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the Java Naming and Directory Interface (JNDI) API. + * + * @since 9 */ module java.naming { requires java.security.sasl; diff --git a/jdk/src/java.prefs/share/classes/module-info.java b/jdk/src/java.prefs/share/classes/module-info.java index 4826cd2241b..15c47ad206b 100644 --- a/jdk/src/java.prefs/share/classes/module-info.java +++ b/jdk/src/java.prefs/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the Preferences API. + * + * @since 9 */ module java.prefs { requires java.xml; diff --git a/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationInstantiator.java b/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationInstantiator.java index 8652492670b..4e100fb9abb 100644 --- a/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationInstantiator.java +++ b/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationInstantiator.java @@ -60,7 +60,20 @@ public interface ActivationInstantiator extends Remote { * initialization data, and * *

  10. returning a MarshalledObject containing the stub for the - * remote object it created + * remote object it created. + * + *

    In order for activation to be successful, one of the following requirements + * must be met, otherwise {@link ActivationException} is thrown: + * + *

    • The class to be activated and the special activation constructor are both public, + * and the class resides in a package that is + * {@linkplain java.lang.reflect.Module#isExported(String,java.lang.reflect.Module) exported} + * to at least the {@code java.rmi} module; or + * + *
    • The class to be activated resides in a package that is + * {@linkplain java.lang.reflect.Module#isOpen(String,java.lang.reflect.Module) open} + * to at least the {@code java.rmi} module. + *
    * * @param id the object's activation identifier * @param desc the object's descriptor diff --git a/jdk/src/java.rmi/share/classes/java/rmi/activation/Activator.java b/jdk/src/java.rmi/share/classes/java/rmi/activation/Activator.java index 18fd82ca3a1..dca2b69b089 100644 --- a/jdk/src/java.rmi/share/classes/java/rmi/activation/Activator.java +++ b/jdk/src/java.rmi/share/classes/java/rmi/activation/Activator.java @@ -48,7 +48,7 @@ import java.rmi.activation.UnknownObjectException; * The Activator works closely with * ActivationSystem, which provides a means for registering * groups and objects within those groups, and ActivationMonitor, - * which recives information about active and inactive objects and inactive + * which receives information about active and inactive objects and inactive * groups.

    * * The activator is responsible for monitoring and detecting when diff --git a/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java b/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java index f18c66eaf4a..ecc1b6590bd 100644 --- a/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java +++ b/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java @@ -107,8 +107,9 @@ import sun.rmi.transport.LiveRef; * the binary name of the root class with the suffix {@code _Stub}. * *

  11. The stub class is loaded by name using the class loader of the root - * class. The stub class must extend {@link RemoteStub} and must have a - * public constructor that has one parameter of type {@link RemoteRef}. + * class. The stub class must be public, it must extend {@link RemoteStub}, it must + * reside in a package that is exported to at least the {@code java.rmi} module, and it + * must have a public constructor that has one parameter of type {@link RemoteRef}. * *
  12. Finally, an instance of the stub class is constructed with a * {@link RemoteRef}. @@ -124,12 +125,21 @@ import sun.rmi.transport.LiveRef; * *
      * - *
    • The proxy's class is defined by the class loader of the remote - * object's class. + *
    • The proxy's class is defined according to the specifications for the + * + * {@code Proxy} + * + * class, using the class loader of the remote object's class. * *
    • The proxy implements all the remote interfaces implemented by the * remote object's class. * + *
    • Each remote interface must either be public and reside in a package that is + * {@linkplain java.lang.reflect.Module#isExported(String,java.lang.reflect.Module) exported} + * to at least the {@code java.rmi} module, or it must reside in a package that is + * {@linkplain java.lang.reflect.Module#isOpen(String,java.lang.reflect.Module) open} + * to at least the {@code java.rmi} module. + * *
    • The proxy's invocation handler is a {@link * RemoteObjectInvocationHandler} instance constructed with a * {@link RemoteRef}. diff --git a/jdk/src/java.rmi/share/classes/module-info.java b/jdk/src/java.rmi/share/classes/module-info.java index 7b975859f12..b10be8aee8e 100644 --- a/jdk/src/java.rmi/share/classes/module-info.java +++ b/jdk/src/java.rmi/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the Remote Method Invocation (RMI) API. + * + * @since 9 */ module java.rmi { requires java.logging; diff --git a/jdk/src/java.scripting/share/classes/module-info.java b/jdk/src/java.scripting/share/classes/module-info.java index b0a5baffc39..0ee7a489b1f 100644 --- a/jdk/src/java.scripting/share/classes/module-info.java +++ b/jdk/src/java.scripting/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the Scripting API. + * + * @since 9 */ module java.scripting { exports javax.script; diff --git a/jdk/src/java.se.ee/share/classes/module-info.java b/jdk/src/java.se.ee/share/classes/module-info.java index a9caf752162..0156b7abe68 100644 --- a/jdk/src/java.se.ee/share/classes/module-info.java +++ b/jdk/src/java.se.ee/share/classes/module-info.java @@ -28,6 +28,8 @@ *

      * This module requires {@code java.se} and supplements it with modules * that define CORBA and Java EE APIs. These modules are upgradeable. + * + * @since 9 */ @SuppressWarnings("deprecation") module java.se.ee { diff --git a/jdk/src/java.se/share/classes/module-info.java b/jdk/src/java.se/share/classes/module-info.java index 1e1c0ed6abd..4d0d87869f3 100644 --- a/jdk/src/java.se/share/classes/module-info.java +++ b/jdk/src/java.se/share/classes/module-info.java @@ -28,6 +28,8 @@ *

      * The modules defining CORBA and Java EE APIs are not required by * this module, but they are required by {@code java.se.ee}. + * + * @since 9 */ module java.se { requires transitive java.compiler; diff --git a/jdk/src/java.security.jgss/share/classes/module-info.java b/jdk/src/java.security.jgss/share/classes/module-info.java index 78a72496ace..4bb35fd807d 100644 --- a/jdk/src/java.security.jgss/share/classes/module-info.java +++ b/jdk/src/java.security.jgss/share/classes/module-info.java @@ -27,6 +27,8 @@ * Defines the Java binding of the IETF Generic Security Services API (GSS-API). *

      * This module also contains GSS-API mechanisms including Kerberos v5 and SPNEGO. + * + * @since 9 */ module java.security.jgss { requires java.naming; diff --git a/jdk/src/java.security.sasl/share/classes/module-info.java b/jdk/src/java.security.sasl/share/classes/module-info.java index 70f860b3ce9..0f4e1fd9f1f 100644 --- a/jdk/src/java.security.sasl/share/classes/module-info.java +++ b/jdk/src/java.security.sasl/share/classes/module-info.java @@ -29,6 +29,8 @@ *

      * This module also contains SASL mechanisms including DIGEST-MD5, * CRAM-MD5, and NTLM. + * + * @since 9 */ module java.security.sasl { requires java.logging; diff --git a/jdk/src/java.smartcardio/share/classes/module-info.java b/jdk/src/java.smartcardio/share/classes/module-info.java index 05f4588cbf6..1b3f717e374 100644 --- a/jdk/src/java.smartcardio/share/classes/module-info.java +++ b/jdk/src/java.smartcardio/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the Java Smart Card I/O API. + * + * @since 9 */ module java.smartcardio { exports javax.smartcardio; diff --git a/jdk/src/java.sql.rowset/share/classes/module-info.java b/jdk/src/java.sql.rowset/share/classes/module-info.java index b2c27bc40cb..5ba5fc96ecd 100644 --- a/jdk/src/java.sql.rowset/share/classes/module-info.java +++ b/jdk/src/java.sql.rowset/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the JDBC RowSet API. + * + * @since 9 */ module java.sql.rowset { requires transitive java.logging; diff --git a/jdk/src/java.sql/share/classes/module-info.java b/jdk/src/java.sql/share/classes/module-info.java index 14491db0b56..9f3c08106c1 100644 --- a/jdk/src/java.sql/share/classes/module-info.java +++ b/jdk/src/java.sql/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the JDBC API. + * + * @since 9 */ module java.sql { requires transitive java.logging; diff --git a/jdk/src/java.transaction/share/classes/module-info.java b/jdk/src/java.transaction/share/classes/module-info.java index 4e245123b4b..f6918b0a130 100644 --- a/jdk/src/java.transaction/share/classes/module-info.java +++ b/jdk/src/java.transaction/share/classes/module-info.java @@ -28,6 +28,8 @@ *

      * The subset consists of RMI exception types which are mapped to CORBA system * exceptions by the 'Java Language to IDL Mapping Specification'. + * + * @since 9 */ module java.transaction { requires transitive java.rmi; diff --git a/jdk/src/java.xml.crypto/share/classes/module-info.java b/jdk/src/java.xml.crypto/share/classes/module-info.java index 4bd55f98b59..ad2f50e9570 100644 --- a/jdk/src/java.xml.crypto/share/classes/module-info.java +++ b/jdk/src/java.xml.crypto/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines an API for XML cryptography. + * + * @since 9 */ module java.xml.crypto { requires transitive java.xml; diff --git a/jdk/src/jdk.attach/share/classes/module-info.java b/jdk/src/jdk.attach/share/classes/module-info.java index d87b33904ce..c23210ab3e8 100644 --- a/jdk/src/jdk.attach/share/classes/module-info.java +++ b/jdk/src/jdk.attach/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the attach API. + * + * @since 9 */ module jdk.attach { requires jdk.internal.jvmstat; diff --git a/jdk/src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg b/jdk/src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg index 5ccefad1369..cba2ffc94f8 100644 --- a/jdk/src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg +++ b/jdk/src/jdk.crypto.ucrypto/solaris/conf/security/ucrypto-solaris.cfg @@ -2,8 +2,5 @@ # Configuration file for the OracleUcrypto provider # disabledServices = { - # disabled due to Solaris bug 7121679 - Cipher.AES/CFB128/PKCS5Padding - Cipher.AES/CFB128/NoPadding } diff --git a/jdk/src/jdk.editpad/share/classes/module-info.java b/jdk/src/jdk.editpad/share/classes/module-info.java index ddf4bee6212..0d674bbae56 100644 --- a/jdk/src/jdk.editpad/share/classes/module-info.java +++ b/jdk/src/jdk.editpad/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Implementation of the edit pad service. + * + * @since 9 */ module jdk.editpad { requires jdk.internal.ed; diff --git a/jdk/src/jdk.incubator.httpclient/share/classes/module-info.java b/jdk/src/jdk.incubator.httpclient/share/classes/module-info.java index 5b8f0c5ac3d..a9a16dfe3d1 100644 --- a/jdk/src/jdk.incubator.httpclient/share/classes/module-info.java +++ b/jdk/src/jdk.incubator.httpclient/share/classes/module-info.java @@ -26,6 +26,8 @@ /** * Defines the high-level HTTP and WebSocket API. * {@Incubating} + * + * @since 9 */ module jdk.incubator.httpclient { requires java.base; diff --git a/jdk/src/jdk.internal.ed/share/classes/module-info.java b/jdk/src/jdk.internal.ed/share/classes/module-info.java index f6beda70a0b..0e0ea99c9d9 100644 --- a/jdk/src/jdk.internal.ed/share/classes/module-info.java +++ b/jdk/src/jdk.internal.ed/share/classes/module-info.java @@ -26,6 +26,8 @@ /** * Internal editor support for JDK tools. Includes the Service Provider * Interface to built-in editors. + * + * @since 9 */ module jdk.internal.ed { diff --git a/jdk/src/jdk.internal.le/share/classes/module-info.java b/jdk/src/jdk.internal.le/share/classes/module-info.java index db859df2a8c..d45879d7587 100644 --- a/jdk/src/jdk.internal.le/share/classes/module-info.java +++ b/jdk/src/jdk.internal.le/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Internal API for line editing + * + * @since 9 */ module jdk.internal.le { exports jdk.internal.jline to diff --git a/jdk/src/jdk.internal.opt/share/classes/module-info.java b/jdk/src/jdk.internal.opt/share/classes/module-info.java index be862b7d532..2bc55831c78 100644 --- a/jdk/src/jdk.internal.opt/share/classes/module-info.java +++ b/jdk/src/jdk.internal.opt/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Internal option processing API + * + * @since 9 */ module jdk.internal.opt { exports jdk.internal.joptsimple to jdk.jlink, jdk.jshell; diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java index 601a5371932..a95ccd8e116 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java @@ -157,8 +157,7 @@ class GNUStyleOptions { for (String dir : dirs) { paths[i++] = Paths.get(dir); } - jartool.moduleFinder = - new ModulePath(Runtime.version(), true, paths); + jartool.moduleFinder = ModulePath.of(Runtime.version(), true, paths); } }, new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") { diff --git a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index 36e2ad3b78b..e0d617bd029 100644 --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -699,7 +699,7 @@ public class Main { } String pn = toPackageName(name); // add if this is a class or resource in a package - if (Checks.isJavaIdentifier(pn)) { + if (Checks.isPackageName(pn)) { packages.add(pn); } } @@ -1995,7 +1995,7 @@ public class Main { } // get a resolved module graph Configuration config = - Configuration.empty().resolveRequires(system, finder, roots); + Configuration.empty().resolve(system, finder, roots); // filter modules resolved from the system module finder this.modules = config.modules().stream() diff --git a/jdk/src/jdk.jdi/share/classes/module-info.java b/jdk/src/jdk.jdi/share/classes/module-info.java index 0dd61c61c49..e2cb439d8c0 100644 --- a/jdk/src/jdk.jdi/share/classes/module-info.java +++ b/jdk/src/jdk.jdi/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Defines the Java Debugger Interface. + * + * @since 9 */ module jdk.jdi { requires jdk.attach; diff --git a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java index ee7a047fa3f..b78275fab92 100644 --- a/jdk/src/jdk.jdwp.agent/share/classes/module-info.java +++ b/jdk/src/jdk.jdwp.agent/share/classes/module-info.java @@ -25,6 +25,8 @@ /** * Java Debug Wire Protocol. + * + * @since 9 */ module jdk.jdwp.agent { } diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties index 13faa3b40e4..2bc96bd30af 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jimage/resources/jimage.properties @@ -98,3 +98,4 @@ err.not.a.jimage=not a jimage file: {0} err.no.jimage=no jimage provided err.option.unsupported={0} not supported: {1} err.unknown.option=unknown option: {0} +err.cannot.create.dir=cannot create directory {0} diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 0eb7ade59fa..40413d491ca 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; +import java.lang.module.FindException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; @@ -232,7 +233,7 @@ public class JlinkTask { return EXIT_OK; } catch (PluginException | IllegalArgumentException | - UncheckedIOException |IOException | ResolutionException e) { + UncheckedIOException |IOException | FindException | ResolutionException e) { log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage()); if (DEBUG) { e.printStackTrace(log); @@ -370,7 +371,7 @@ public class JlinkTask { */ private ModuleFinder modulePathFinder() { Path[] entries = options.modulePath.toArray(new Path[0]); - ModuleFinder finder = new ModulePath(Runtime.version(), true, entries); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries); if (!options.limitMods.isEmpty()) { finder = limitFinder(finder, options.limitMods, Collections.emptySet()); } @@ -388,7 +389,7 @@ public class JlinkTask { Set roots) { Path[] entries = paths.toArray(new Path[0]); - ModuleFinder finder = new ModulePath(Runtime.version(), true, entries); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries); // if limitmods is specified then limit the universe if (!limitMods.isEmpty()) { @@ -418,9 +419,9 @@ public class JlinkTask { } Configuration cf = Configuration.empty() - .resolveRequires(finder, - ModuleFinder.of(), - roots); + .resolve(finder, + ModuleFinder.of(), + roots); // emit warning for modules that end with a digit cf.modules().stream() @@ -458,9 +459,9 @@ public class JlinkTask { // resolve all root modules Configuration cf = Configuration.empty() - .resolveRequires(finder, - ModuleFinder.of(), - roots); + .resolve(finder, + ModuleFinder.of(), + roots); // module name -> reference Map map = new HashMap<>(); diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java index 9c81c7740c6..37d96c64413 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java @@ -51,7 +51,7 @@ final class ResourcePoolConfiguration { ModuleDescriptor md = mod.descriptor(); // drop hashes - ModuleDescriptor.Builder builder = ModuleDescriptor.module(md.name()); + ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(md.name()); md.requires().stream() .forEach(builder::requires); md.exports().stream() @@ -62,12 +62,7 @@ final class ResourcePoolConfiguration { .forEach(builder::uses); md.provides().stream() .forEach(builder::provides); - - // build the proper concealed packages - Set concealed = new HashSet<>(mod.packages()); - md.exports().stream().map(ModuleDescriptor.Exports::source).forEach(concealed::remove); - md.opens().stream().map(ModuleDescriptor.Opens::source).forEach(concealed::remove); - concealed.stream().forEach(builder::contains); + builder.packages(md.packages()); md.version().ifPresent(builder::version); md.mainClass().ifPresent(builder::mainClass); @@ -124,7 +119,7 @@ final class ResourcePoolConfiguration { } }; - return Configuration.empty().resolveRequires( + return Configuration.empty().resolve( finder, ModuleFinder.of(), nameToModRef.keySet()); } } diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index 7c60d79657e..2f45403a27c 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -718,13 +718,13 @@ public final class TaskHelper { static Layer createPluginsLayer(List paths) { Path[] dirs = paths.toArray(new Path[0]); - ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, dirs); Configuration bootConfiguration = Layer.boot().configuration(); try { Configuration cf = bootConfiguration - .resolveRequiresAndUses(ModuleFinder.of(), - finder, - Collections.emptySet()); + .resolveAndBind(ModuleFinder.of(), + finder, + Collections.emptySet()); ClassLoader scl = ClassLoader.getSystemClassLoader(); return Layer.boot().defineModulesWithOneLoader(cf, scl); } catch (Exception ex) { diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java index 8c3f3ea114e..14cd3f501a4 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java @@ -771,9 +771,12 @@ public final class SystemModulesPlugin implements Plugin { if (md.isOpen()) { setModuleBit("open", true); } - if (md.isSynthetic()) { + if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) { setModuleBit("synthetic", true); } + if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED)) { + setModuleBit("mandated", true); + } } /* diff --git a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java index 3ed482b7d99..be88c492297 100644 --- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java +++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java @@ -34,6 +34,7 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.module.Configuration; +import java.lang.module.FindException; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.lang.module.ModuleFinder; @@ -851,8 +852,8 @@ public class JmodTask { // get a resolved module graph Configuration config = null; try { - config = Configuration.empty().resolveRequires(system, finder, roots); - } catch (ResolutionException e) { + config = Configuration.empty().resolve(system, finder, roots); + } catch (FindException | ResolutionException e) { throw new CommandException("err.module.resolution.fail", e.getMessage()); } @@ -1392,7 +1393,7 @@ public class JmodTask { options.legalNotices = getLastElement(opts.valuesOf(legalNotices)); if (opts.has(modulePath)) { Path[] dirs = getLastElement(opts.valuesOf(modulePath)).toArray(new Path[0]); - options.moduleFinder = new ModulePath(Runtime.version(), true, dirs); + options.moduleFinder = ModulePath.of(Runtime.version(), true, dirs); } if (opts.has(moduleVersion)) options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion)); diff --git a/jdk/src/jdk.security.auth/share/classes/module-info.java b/jdk/src/jdk.security.auth/share/classes/module-info.java index 4675b238e19..1f6eea6537b 100644 --- a/jdk/src/jdk.security.auth/share/classes/module-info.java +++ b/jdk/src/jdk.security.auth/share/classes/module-info.java @@ -26,6 +26,8 @@ /** * Contains the implementation of the javax.security.auth.* interfaces and * various authentication modules. + * + * @since 9 */ module jdk.security.auth { requires transitive java.naming; diff --git a/jdk/src/jdk.security.jgss/share/classes/module-info.java b/jdk/src/jdk.security.jgss/share/classes/module-info.java index e66017f0102..f43fdd49296 100644 --- a/jdk/src/jdk.security.jgss/share/classes/module-info.java +++ b/jdk/src/jdk.security.jgss/share/classes/module-info.java @@ -26,6 +26,8 @@ /** * Defines Java extensions to the GSS-API and an implementation of the SASL * GSSAPI mechanism. + * + * @since 9 */ module jdk.security.jgss { requires transitive java.security.jgss; diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index f94c56a05e4..0162d67b35c 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -251,12 +251,11 @@ sanity/client/SwingSet/src/ButtonDemoScreenshotTest.java 8157338 generic- tools/pack200/CommandLineTests.java 8059906 generic-all -tools/launcher/ArgsEnvVar.java 8173712 generic-all tools/launcher/FXLauncherTest.java 8068049 linux-all,macosx-all -tools/jimage/JImageExtractTest.java 8169713 generic-all -tools/jimage/JImageListTest.java 8169713 generic-all -tools/jimage/JImageVerifyTest.java 8169713 generic-all +tools/jimage/JImageExtractTest.java 8170120 generic-all +tools/jimage/JImageListTest.java 8170120 generic-all +tools/jimage/JImageVerifyTest.java 8170120 generic-all tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java 8169971 windows-x64 @@ -267,7 +266,7 @@ tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java 8169971 windows- com/sun/jdi/RedefineImplementor.sh 8004127 generic-all -com/sun/jdi/JdbMethodExitTest.sh 6902121 generic-all +com/sun/jdi/JdbMethodExitTest.sh 8171483 generic-all com/sun/jdi/RepStep.java 8043571 generic-all @@ -296,6 +295,8 @@ java/util/BitSet/BitSetStreamTest.java 8079538 generic- sun/tools/jcmd/TestJcmdSanity.java 8031482 windows-all +sun/tools/jstat/jstatClassloadOutput1.sh 8173942 generic-all + sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java 8057732 generic-all demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java 8151899 generic-all @@ -308,6 +309,6 @@ com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java 8169942 linux-i5 javax/rmi/PortableRemoteObject/8146975/RmiIiopReturnValueTest.java 8169737 linux-all -javax/xml/ws/clientjar/TestWsImport.java 8170370 generic-all +javax/xml/ws/clientjar/TestWsImport.java 8173317 generic-all ############################################################################ diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index 3c8b8c60caf..c682ce2c41b 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -273,6 +273,7 @@ jdk_other = \ jdk/internal/jline \ com/sun/jndi \ com/sun/corba \ + org/omg/CORBA \ lib/testlibrary \ sample diff --git a/jdk/test/com/oracle/security/ucrypto/TestAES.java b/jdk/test/com/oracle/security/ucrypto/TestAES.java index 717e3186d97..bf460d420a6 100644 --- a/jdk/test/com/oracle/security/ucrypto/TestAES.java +++ b/jdk/test/com/oracle/security/ucrypto/TestAES.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +23,7 @@ /* * @test - * @bug 7088989 8014374 8167512 + * @bug 7088989 8014374 8167512 8173708 * @summary Ensure the AES ciphers of OracleUcrypto provider works correctly * @key randomness * @run main TestAES @@ -177,6 +177,12 @@ public class TestAES extends UcryptoTest { k += c.doFinal(eout, firstPartLen+1, eout.length - firstPartLen - 1, dout, k); if (!checkArrays(in, in.length, dout, k)) testPassed = false; } catch(Exception ex) { + if (ex instanceof BadPaddingException && + algos[i].indexOf("CFB128") != -1 && + p.getName().equals("OracleUcrypto")) { + System.out.println("Ignore due to a pre-S11.3 bug: " + ex); + continue; + } System.out.println("Unexpected Exception: " + algos[i]); ex.printStackTrace(); testPassed = false; diff --git a/jdk/test/java/io/FilePermission/ReadFileOnPath.java b/jdk/test/java/io/FilePermission/ReadFileOnPath.java index 42ed7542030..9ce8fb9b006 100644 --- a/jdk/test/java/io/FilePermission/ReadFileOnPath.java +++ b/jdk/test/java/io/FilePermission/ReadFileOnPath.java @@ -57,7 +57,7 @@ public class ReadFileOnPath { "module-info.class", "base", "p/App.class", "p/child"); // exploded module - test("--module-path", "modules", "-m", "m/p.App", "SS+++++"); + test("--module-path", "modules", "-m", "m/p.App", "SS++++0"); // module in jar test("--module-path", "new.jar", "-m", "m/p.App", "SSSS++0"); diff --git a/jdk/test/java/lang/Class/forName/modules/TestLayer.java b/jdk/test/java/lang/Class/forName/modules/TestLayer.java index 645e04d7e9b..ff9a772ceeb 100644 --- a/jdk/test/java/lang/Class/forName/modules/TestLayer.java +++ b/jdk/test/java/lang/Class/forName/modules/TestLayer.java @@ -46,9 +46,9 @@ public class TestLayer { ModuleFinder finder = ModuleFinder.of(MODS_DIR); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequiresAndUses(ModuleFinder.of(), - finder, - modules); + Configuration cf = parent.resolveAndBind(ModuleFinder.of(), + finder, + modules); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); diff --git a/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java index 618b2fde67a..25e8779ab48 100644 --- a/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java +++ b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java @@ -50,9 +50,9 @@ public class NoAccess { Layer bootLayer = Layer.boot(); Configuration parent = bootLayer.configuration(); - Configuration cf = parent.resolveRequiresAndUses(finder, - ModuleFinder.of(), - Set.of("m1", "m2")); + Configuration cf = parent.resolveAndBind(finder, + ModuleFinder.of(), + Set.of("m1", "m2")); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithManyLoaders(cf, scl); diff --git a/jdk/test/java/lang/Class/getPackageName/Basic.java b/jdk/test/java/lang/Class/getPackageName/Basic.java index e0c0bd17d3c..c079d653205 100644 --- a/jdk/test/java/lang/Class/getPackageName/Basic.java +++ b/jdk/test/java/lang/Class/getPackageName/Basic.java @@ -154,8 +154,8 @@ public class Basic { return new Object[][] { { Basic.class, TEST_PACKAGE }, - { Basic[].class, null }, - { Basic[][].class, null }, + { Basic[].class, TEST_PACKAGE }, + { Basic[][].class, TEST_PACKAGE }, { getNestedClass1(), TEST_PACKAGE }, { getNestedClass2(), TEST_PACKAGE }, @@ -174,14 +174,14 @@ public class Basic { { getAnonymousClass6(), TEST_PACKAGE }, { Object.class, "java.lang" }, - { Object[].class, null }, - { Object[][].class, null }, + { Object[].class, "java.lang" }, + { Object[][].class, "java.lang" }, - { int.class, null }, - { int[].class, null }, - { int[][].class, null }, + { int.class, "java.lang" }, + { int[].class, "java.lang" }, + { int[][].class, "java.lang" }, - { void.class, null }, + { void.class, "java.lang" }, }; } diff --git a/jdk/test/java/lang/ClassLoader/securityManager/ClassLoaderTest.java b/jdk/test/java/lang/ClassLoader/securityManager/ClassLoaderTest.java new file mode 100644 index 00000000000..055de8f38f5 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/securityManager/ClassLoaderTest.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8168423 + * @summary Different types of ClassLoader running with(out) SecurityManager and + * (in)valid security policy file. + * @library /lib/testlibrary + * @modules java.base/jdk.internal.module + * @build JarUtils CompilerUtils + * @run main/timeout=240 ClassLoaderTest + */ +import java.io.File; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Map; +import java.util.HashMap; +import java.lang.module.ModuleDescriptor; +import jdk.internal.module.ModuleInfoWriter; +import jdk.testlibrary.ProcessTools; + +public class ClassLoaderTest { + + private static final String SRC = System.getProperty("test.src"); + private static final Path CL_SRC = Paths.get(SRC, "TestClassLoader.java"); + private static final Path C_SRC = Paths.get(SRC, "TestClient.java"); + private static final Path CL_BIN = Paths.get("classes", "clbin"); + private static final Path C_BIN = Paths.get("classes", "cbin"); + private static final Path ARTIFACT_DIR = Paths.get("jars"); + private static final Path VALID_POLICY = Paths.get(SRC, "valid.policy"); + private static final Path INVALID_POLICY + = Paths.get(SRC, "malformed.policy"); + private static final Path NO_POLICY = null; + private static final String LOCALE = "-Duser.language=en -Duser.region=US"; + /* + * Here is the naming convention followed for each jar. + * cl.jar - Regular custom class loader jar. + * mcl.jar - Modular custom class loader jar. + * c.jar - Regular client jar. + * mc.jar - Modular client jar. + * amc.jar - Modular client referring automated custom class loader jar. + */ + private static final Path CL_JAR = ARTIFACT_DIR.resolve("cl.jar"); + private static final Path MCL_JAR = ARTIFACT_DIR.resolve("mcl.jar"); + private static final Path C_JAR = ARTIFACT_DIR.resolve("c.jar"); + private static final Path MC_JAR = ARTIFACT_DIR.resolve("mc.jar"); + private static final Path AMC_JAR = ARTIFACT_DIR.resolve("amc.jar"); + private static final Map MSG_MAP = new HashMap<>(); + + static { + // This mapping help process finding expected message based + // on the key passed as argument while executing java command. + MSG_MAP.put("MissingModule", "Module cl not found, required by mc"); + MSG_MAP.put("ErrorPolicy", "java.security.policy: error parsing file"); + MSG_MAP.put( + "SystemCL", "jdk.internal.loader.ClassLoaders$AppClassLoader"); + MSG_MAP.put("CustomCL", "cl.TestClassLoader"); + } + + public static void main(String[] args) throws Exception { + + // Generates regular and modular jars before start processing it. + setUp(); + processForEachPolicyFile(); + } + + /** + * Test cases are based on the following logic, + * for (policyFile : {"NO_POLICY", "VALID", "MALFORMED"}) { + * for (classLoader : {"SystemClassLoader", "CustomClassLoader"}){ + * for (clientModule : {"NAMED", "AUTOMATIC", "UNNAMED"}) { + * for (classLoaderModule : {"NAMED", "AUTOMATIC", "UNNAMED"}) { + * Create and run java command for each possible Test case + * } + * } + * } + * } + */ + private static void processForEachPolicyFile() throws Exception { + + final String regCLloc = CL_JAR.toFile().getAbsolutePath(); + final String modCLloc = MCL_JAR.toFile().getAbsolutePath(); + final String regCloc = C_JAR.toFile().getAbsolutePath(); + final String modCloc = MC_JAR.toFile().getAbsolutePath(); + final String autoModCloc = AMC_JAR.toFile().getAbsolutePath(); + final String separator = File.pathSeparator; + + for (Path policy + : new Path[]{NO_POLICY, VALID_POLICY, INVALID_POLICY}) { + final String policyFile = (policy != null) + ? policy.toFile().getAbsolutePath() : null; + final boolean malformedPolicy + = (policy == null) ? false : policy.equals(INVALID_POLICY); + + for (boolean useSCL : new boolean[]{true, false}) { + final String clVmArg = (useSCL) ? "" + : "-Djava.system.class.loader=cl.TestClassLoader"; + final String autoAddModArg + = (useSCL) ? "" : "--add-modules=cl"; + final String addmodArg = (useSCL) ? "" : "--add-modules=mcl"; + final String sMArg = (policy != null) ? String.format( + "-Djava.security.manager -Djava.security.policy=%s", + policyFile) : ""; + final String smMsg = (policy != null) ? "With SecurityManager" + : "Without SecurityManager"; + final String expectedResult = ((!malformedPolicy) + ? ((useSCL) ? "PASS SystemCL" : "PASS CustomCL") + : "FAIL ErrorPolicy"); + + // NAMED-NAMED, NAMED-AUTOMATIC, NAMED-UNNAMED + System.out.printf("Case:- Modular Client and %s %s%n", + ((useSCL) ? "SystemClassLoader" + : "Modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "--module-path %s%s%s %s %s %s -m mc/c.TestClient", + modCloc, separator, modCLloc, LOCALE, clVmArg, sMArg), + expectedResult}); + System.out.printf("Case:- Modular Client and %s %s%n", ((useSCL) + ? "SystemClassLoader" + : "Automatic modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "--module-path %s%s%s %s %s %s -m mc/c.TestClient", + autoModCloc, separator, regCLloc, LOCALE, clVmArg, sMArg), + expectedResult}); + System.out.printf("Case:- Modular Client and %s %s%n", ((useSCL) + ? "SystemClassLoader" + : "Unknown modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "--module-path %s -cp %s %s %s %s -m mc/c.TestClient", + autoModCloc, regCLloc, LOCALE, clVmArg, sMArg), + "FAIL MissingModule"}); + + // AUTOMATIC-NAMED, AUTOMATIC-AUTOMATIC, AUTOMATIC-UNNAMED + System.out.printf("Case:- Automated modular Client and %s %s%n", + ((useSCL) ? "SystemClassLoader" + : "Modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "--module-path %s%s%s %s %s %s %s -m c/c.TestClient", + regCloc, separator, modCLloc, addmodArg, LOCALE, clVmArg, + sMArg), expectedResult}); + System.out.printf("Case:- Automated modular Client and %s %s%n", + ((useSCL) ? "SystemClassLoader" + : "Automatic modular CustomClassLoader"), + smMsg); + execute(new String[]{String.format( + "--module-path %s%s%s %s %s %s %s -m c/c.TestClient", + regCloc, separator, regCLloc, autoAddModArg, LOCALE, + clVmArg, sMArg), expectedResult}); + System.out.printf("Case:- Automated modular Client and %s %s%n", + ((useSCL) ? "SystemClassLoader" + : "Unknown modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "--module-path %s -cp %s %s %s %s -m c/c.TestClient", + regCloc, regCLloc, LOCALE, clVmArg, sMArg), + expectedResult}); + + // UNNAMED-NAMED, UNNAMED-AUTOMATIC, UNNAMED-UNNAMED + System.out.printf("Case:- Unknown modular Client and %s %s%n", + ((useSCL) ? "SystemClassLoader" + : "Modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "-cp %s --module-path %s %s %s %s %s c.TestClient", + regCloc, modCLloc, addmodArg, LOCALE, clVmArg, sMArg), + expectedResult}); + System.out.printf("Case:- Unknown modular Client and %s %s%n", + ((useSCL) ? "SystemClassLoader" + : "Automatic modular CustomClassLoader"), + smMsg); + execute(new String[]{String.format( + "-cp %s --module-path %s %s %s %s %s c.TestClient", + regCloc, regCLloc, autoAddModArg, LOCALE, clVmArg, sMArg), + expectedResult}); + System.out.printf("Case:- Unknown modular Client and %s %s%n", + ((useSCL) ? "SystemClassLoader" + : "Unknown modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "-cp %s%s%s %s %s %s c.TestClient", regCloc, separator, + regCLloc, LOCALE, clVmArg, sMArg), expectedResult}); + + // Regular jars in module-path and Modular jars in class-path. + System.out.printf("Case:- Regular Client and %s " + + "inside --module-path %s.%n", ((useSCL) + ? "SystemClassLoader" + : "Unknown modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "--module-path %s%s%s %s %s %s %s -m c/c.TestClient", + regCloc, separator, regCLloc, autoAddModArg, LOCALE, + clVmArg, sMArg), expectedResult}); + System.out.printf("Case:- Modular Client and %s in -cp %s%n", + ((useSCL) ? "SystemClassLoader" + : "Modular CustomClassLoader"), smMsg); + execute(new String[]{String.format( + "-cp %s%s%s %s %s %s c.TestClient", modCloc, separator, + modCLloc, LOCALE, clVmArg, sMArg), expectedResult}); + } + } + } + + /** + * Execute with command arguments and process the result. + */ + private static void execute(String[] args) throws Exception { + + String status = null; + String msgKey = null; + if ((args != null && args.length > 1)) { + String[] secArgs = args[1].split("\\s+"); + status = (secArgs.length > 0) ? secArgs[0] : null; + msgKey = (secArgs.length > 1) ? secArgs[1] : null; + } + String out = ProcessTools.executeTestJvm(args[0].split("\\s+")) + .getOutput(); + // Handle response. + if ((status != null && "PASS".equals(status) && msgKey != null + && out.contains(MSG_MAP.get(msgKey)))) { + System.out.printf("PASS: Expected Result: %s.%n", + MSG_MAP.get(msgKey)); + } else if ((status != null && "FAIL".equals(status) && msgKey != null + && out.contains(MSG_MAP.get(msgKey)))) { + System.out.printf("PASS: Expected Failure: %s.%n", + MSG_MAP.get(msgKey)); + } else if (out.contains("Exception") || out.contains("Error")) { + System.out.printf("OUTPUT: %s", out); + throw new RuntimeException("FAIL: Unknown Exception."); + } else { + System.out.printf("OUTPUT: %s", out); + throw new RuntimeException("FAIL: Unknown Test case found"); + } + } + + /** + * Creates regular/modular jar files for TestClient and TestClassLoader. + */ + private static void setUp() throws Exception { + + boolean compiled = CompilerUtils.compile(CL_SRC, CL_BIN); + compiled &= CompilerUtils.compile(C_SRC, C_BIN); + if (!compiled) { + throw new RuntimeException("Test Setup failed."); + } + // Generate regular jar files for TestClient and TestClassLoader + JarUtils.createJarFile(CL_JAR, CL_BIN); + JarUtils.createJarFile(C_JAR, C_BIN); + // Generate modular jar files for TestClient and TestClassLoader with + // their corresponding ModuleDescriptor. + Files.copy(CL_JAR, MCL_JAR, StandardCopyOption.REPLACE_EXISTING); + updateModuleDescr(MCL_JAR, ModuleDescriptor.newModule("mcl") + .exports("cl").requires("java.base").build()); + Files.copy(C_JAR, MC_JAR, StandardCopyOption.REPLACE_EXISTING); + updateModuleDescr(MC_JAR, ModuleDescriptor.newModule("mc") + .exports("c").requires("java.base").requires("mcl").build()); + Files.copy(C_JAR, AMC_JAR, StandardCopyOption.REPLACE_EXISTING); + updateModuleDescr(AMC_JAR, ModuleDescriptor.newModule("mc") + .exports("c").requires("java.base").requires("cl").build()); + } + + /** + * Update regular jars and include module-info.class inside it to make + * modular jars. + */ + private static void updateModuleDescr(Path jar, ModuleDescriptor mDescr) + throws Exception { + if (mDescr != null) { + Path dir = Files.createTempDirectory("tmp"); + Path mi = dir.resolve("module-info.class"); + try (OutputStream out = Files.newOutputStream(mi)) { + ModuleInfoWriter.write(mDescr, out); + } + System.out.format("Adding 'module-info.class' to jar '%s'%n", jar); + JarUtils.updateJarFile(jar, dir); + } + } +} diff --git a/jdk/test/java/lang/ClassLoader/securityManager/TestClassLoader.java b/jdk/test/java/lang/ClassLoader/securityManager/TestClassLoader.java new file mode 100644 index 00000000000..64892ae0638 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/securityManager/TestClassLoader.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 cl; + +public class TestClassLoader extends ClassLoader { + + /** + * This constructor is used to set the parent ClassLoader + */ + public TestClassLoader(ClassLoader parent) { + super(parent); + } + +} diff --git a/jdk/test/java/lang/ClassLoader/securityManager/TestClient.java b/jdk/test/java/lang/ClassLoader/securityManager/TestClient.java new file mode 100644 index 00000000000..de0fe1039e8 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/securityManager/TestClient.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 c; + +public class TestClient { + + public static void main(String[] args) { + + // Initialize policy file. + System.getProperty("test.src"); + System.out.printf("ContextClassLoader: %s%n", + Thread.currentThread().getContextClassLoader().toString()); + } +} diff --git a/jdk/test/java/lang/ClassLoader/securityManager/malformed.policy b/jdk/test/java/lang/ClassLoader/securityManager/malformed.policy new file mode 100644 index 00000000000..8afdf6913dc --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/securityManager/malformed.policy @@ -0,0 +1,4 @@ +grant { + xyz; + permission java.util.PropertyPermission "test.src", "read"; +} \ No newline at end of file diff --git a/jdk/test/java/lang/ClassLoader/securityManager/valid.policy b/jdk/test/java/lang/ClassLoader/securityManager/valid.policy new file mode 100644 index 00000000000..54ef7d0a6d0 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/securityManager/valid.policy @@ -0,0 +1,4 @@ +grant codeBase "file:./jars/*" { + permission java.lang.RuntimePermission "createClassLoader"; + permission java.util.PropertyPermission "test.src", "read"; +}; \ No newline at end of file diff --git a/jdk/test/java/lang/StackWalker/Basic.java b/jdk/test/java/lang/StackWalker/Basic.java index 37e51f08097..8dc7627a90d 100644 --- a/jdk/test/java/lang/StackWalker/Basic.java +++ b/jdk/test/java/lang/StackWalker/Basic.java @@ -23,18 +23,21 @@ /* * @test - * @bug 8140450 + * @bug 8140450 8173898 * @summary Basic test for the StackWalker::walk method * @run testng Basic */ import java.lang.StackWalker.StackFrame; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.lang.StackWalker.Option.*; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import static org.testng.Assert.*; public class Basic { private static boolean verbose = false; @@ -60,6 +63,17 @@ public class Basic { } } + @Test + public static void testWalkFromConstructor() throws Exception { + System.out.println("testWalkFromConstructor:"); + List found = ((ConstructorNewInstance)ConstructorNewInstance.class.getMethod("create") + .invoke(null)).collectedFrames(); + assertEquals(List.of(ConstructorNewInstance.class.getName()+"::", + ConstructorNewInstance.class.getName()+"::create", + Basic.class.getName()+"::testWalkFromConstructor"), + found); + } + private final int depth; Basic(int depth) { this.depth = depth; @@ -77,6 +91,47 @@ public class Basic { assertEquals(limit, frames.size()); } + static class ConstructorNewInstance { + static final StackWalker walker = + StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + List testFramesOrReflectionFrames; + public ConstructorNewInstance() { + testFramesOrReflectionFrames = walker.walk(this::parse); + } + public List collectedFrames() { + return testFramesOrReflectionFrames; + } + public boolean accept(StackFrame f) { + // Frames whose class names don't contain "." + // are our own test frames. These are the ones + // we expect. + // Frames whose class names contain ".reflect." + // are reflection frames. None should be present, + // since they are supposed to be filtered by + // by StackWalker. If we find any, we want to fail. + if (!f.getClassName().contains(".") + || f.getClassName().contains(".reflect.")) { + System.out.println(" " + f); + return true; + } + // Filter out all other frames (in particular + // those from the test framework) in order to + // have predictable results. + return false; + } + public String frame(StackFrame f) { + return f.getClassName() + "::" + f.getMethodName(); + } + List parse(Stream s) { + return s.filter(this::accept) + .map(this::frame) + .collect(Collectors.toList()); + } + public static ConstructorNewInstance create() throws Exception { + return ConstructorNewInstance.class.getConstructor().newInstance(); + } + } + class StackBuilder { private final int stackDepth; private final int limit; @@ -131,9 +186,4 @@ public class Basic { } } - static void assertEquals(int x, int y) { - if (x != y) { - throw new RuntimeException(x + " != " + y); - } - } } diff --git a/jdk/test/java/lang/StackWalker/CallerFromMain.java b/jdk/test/java/lang/StackWalker/CallerFromMain.java index 9bc289a7f38..0eb0b2bdc46 100644 --- a/jdk/test/java/lang/StackWalker/CallerFromMain.java +++ b/jdk/test/java/lang/StackWalker/CallerFromMain.java @@ -51,7 +51,7 @@ public class CallerFromMain { try { Class c = sw.getCallerClass(); throw new RuntimeException("UOE not thrown. Caller: " + c); - } catch (IllegalStateException e) {} + } catch (IllegalCallerException e) {} // StackWalker::getCallerClass // Runnable::run diff --git a/jdk/test/java/lang/StackWalker/CountLocalSlots.java b/jdk/test/java/lang/StackWalker/CountLocalSlots.java deleted file mode 100644 index dfb1698d188..00000000000 --- a/jdk/test/java/lang/StackWalker/CountLocalSlots.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 8147039 - * @summary Confirm locals[] always has expected length, even for "dead" locals - * @modules java.base/java.lang:open - * @compile LocalsAndOperands.java - * @run testng/othervm -Xcomp CountLocalSlots - */ - -import org.testng.annotations.Test; -import java.lang.StackWalker.StackFrame; - -public class CountLocalSlots { - final static boolean debug = true; - - @Test(dataProvider = "provider", dataProviderClass = LocalsAndOperands.class) - public void countLocalSlots(StackFrame... frames) { - for (StackFrame frame : frames) { - if (debug) { - System.out.println("Running countLocalSlots"); - LocalsAndOperands.dumpStackWithLocals(frames); - } - // Confirm expected number of locals - String methodName = frame.getMethodName(); - Integer expectedObj = (Integer) LocalsAndOperands.Tester.NUM_LOCALS.get(methodName); - if (expectedObj == null) { - if (!debug) { LocalsAndOperands.dumpStackWithLocals(frames); } - throw new RuntimeException("No NUM_LOCALS entry for " + - methodName + "(). Update test?"); - } - Object[] locals = (Object[]) LocalsAndOperands.invokeGetLocals(frame); - if (locals.length != expectedObj) { - if (!debug) { LocalsAndOperands.dumpStackWithLocals(frames); } - throw new RuntimeException(methodName + "(): number of locals (" + - locals.length + ") did not match expected (" + expectedObj + ")"); - } - } - } -} diff --git a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java index ab07c7d9ad8..1b9d71b696b 100644 --- a/jdk/test/java/lang/StackWalker/LocalsAndOperands.java +++ b/jdk/test/java/lang/StackWalker/LocalsAndOperands.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * 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,33 +23,54 @@ /* * @test - * @bug 8020968 8147039 + * @bug 8020968 8147039 8156073 * @summary Tests for locals and operands * @modules java.base/java.lang:open - * @run testng LocalsAndOperands + * @run testng/othervm -Xint -DtestUnused=true LocalsAndOperands + * @run testng/othervm -Xcomp LocalsAndOperands + * @run testng/othervm -Xcomp -XX:-TieredCompilation LocalsAndOperands */ import org.testng.annotations.*; +import static org.testng.Assert.*; import java.lang.StackWalker.StackFrame; +import static java.lang.StackWalker.Option.*; import java.lang.reflect.*; import java.util.*; import java.util.stream.*; public class LocalsAndOperands { - static final boolean debug = true; + static final boolean debug = false; + static final boolean is32bit; + static final boolean testUnused; static Class liveStackFrameClass; - static Class primitiveValueClass; + static Class primitiveSlotClass; + static Class primitiveSlot32Class; + static Class primitiveSlot64Class; + static StackWalker extendedWalker; static Method getLocals; static Method getOperands; static Method getMonitors; - static Method primitiveType; + static Method primitiveSize; + static Method primitiveLongValue; + static Method primitiveIntValue; + static Method getExtendedWalker; + + private static final long LOWER_LONG_VAL = 4L; // Lower bits + private static final long UPPER_LONG_VAL = 0x123400000000L; // Upper bits + private static final long NEG_LONG_VAL = Long.MIN_VALUE; + + private static final double LOWER_DOUBLE_VAL = Double.longBitsToDouble(0xABCDL); + private static final double UPPER_DOUBLE_VAL = Double.longBitsToDouble(0x432100000000L); static { try { liveStackFrameClass = Class.forName("java.lang.LiveStackFrame"); - primitiveValueClass = Class.forName("java.lang.LiveStackFrame$PrimitiveValue"); + primitiveSlotClass = Class.forName("java.lang.LiveStackFrame$PrimitiveSlot"); + primitiveSlot32Class = Class.forName("java.lang.LiveStackFrameInfo$PrimitiveSlot32"); + primitiveSlot64Class = Class.forName("java.lang.LiveStackFrameInfo$PrimitiveSlot64"); getLocals = liveStackFrameClass.getDeclaredMethod("getLocals"); getLocals.setAccessible(true); @@ -60,12 +81,31 @@ public class LocalsAndOperands { getMonitors = liveStackFrameClass.getDeclaredMethod("getMonitors"); getMonitors.setAccessible(true); - primitiveType = primitiveValueClass.getDeclaredMethod("type"); - primitiveType.setAccessible(true); + primitiveSize = primitiveSlotClass.getDeclaredMethod("size"); + primitiveSize.setAccessible(true); - Method method = liveStackFrameClass.getMethod("getStackWalker"); - method.setAccessible(true); - extendedWalker = (StackWalker) method.invoke(null); + primitiveLongValue = primitiveSlotClass.getDeclaredMethod("longValue"); + primitiveLongValue.setAccessible(true); + + primitiveIntValue = primitiveSlotClass.getDeclaredMethod("intValue"); + primitiveIntValue.setAccessible(true); + + getExtendedWalker = liveStackFrameClass.getMethod("getStackWalker", Set.class); + getExtendedWalker.setAccessible(true); + extendedWalker = (StackWalker) getExtendedWalker.invoke(null, + EnumSet.noneOf(StackWalker.Option.class)); + + String dataModel = System.getProperty("sun.arch.data.model"); + if ("32".equals(dataModel)) { + is32bit = true; + } else if ("64".equals(dataModel)) { + is32bit= false; + } else { + throw new RuntimeException("Weird data model:" + dataModel); + } + System.out.println("VM bits: " + dataModel); + + testUnused = System.getProperty("testUnused") != null; } catch (Throwable t) { throw new RuntimeException(t); } } @@ -80,47 +120,17 @@ public class LocalsAndOperands { * DataProviders * *****************/ - /** Calls testLocals() and provides LiveStackFrames for testLocals* methods */ + /** Calls KnownLocalsTester.testLocals* and provides LiveStackFrames */ @DataProvider - public static StackFrame[][] provider() { - return new StackFrame[][] { - new Tester().testLocals() - }; - } - - /** - * Calls testLocalsKeepAlive() and provides LiveStackFrames for testLocals* methods. - * Local variables in testLocalsKeepAlive() are ensured to not become dead. - */ - @DataProvider - public static StackFrame[][] keepAliveProvider() { - return new StackFrame[][] { - new Tester().testLocalsKeepAlive() - }; - } - - /** - * Provides StackFrames from a StackWalker without the LOCALS_AND_OPERANDS - * option. - */ - @DataProvider - public static StackFrame[][] noLocalsProvider() { - // Use default StackWalker - return new StackFrame[][] { - new Tester(StackWalker.getInstance(), true).testLocals() - }; - } - - /** - * Calls testLocals() and provides LiveStackFrames for *all* called methods, - * including test infrastructure (jtreg, testng, etc) - * - */ - @DataProvider - public static StackFrame[][] unfilteredProvider() { - return new StackFrame[][] { - new Tester(extendedWalker, false).testLocals() - }; + public static StackFrame[][] knownLocalsProvider() { + List list = new ArrayList<>(3); + list.add(new KnownLocalsTester().testLocalsKeepAlive()); + list.add(new KnownLocalsTester().testLocalsKeepAliveArgs(0xA, 'z', + "himom", 0x3FF00000000L + 0xFFFF, Math.PI)); + if (testUnused) { + list.add(new KnownLocalsTester().testLocalsUnused()); + } + return list.toArray(new StackFrame[1][1]); } /**************** @@ -128,135 +138,123 @@ public class LocalsAndOperands { ****************/ /** - * Check for expected local values and types in the LiveStackFrame + * Check for expected local values in the LiveStackFrame */ - @Test(dataProvider = "keepAliveProvider") + @Test(dataProvider = "knownLocalsProvider") public static void checkLocalValues(StackFrame... frames) { - if (debug) { - System.out.println("Running checkLocalValues"); - dumpStackWithLocals(frames); - } - Arrays.stream(frames).filter(f -> f.getMethodName() - .equals("testLocalsKeepAlive")) - .forEach( - f -> { - Object[] locals = invokeGetLocals(f); - for (int i = 0; i < locals.length; i++) { - // Value - String expected = Tester.LOCAL_VALUES[i]; - Object observed = locals[i]; - if (expected != null /* skip nulls in golden values */ && - !expected.equals(observed.toString())) { - System.err.println("Local value mismatch:"); - if (!debug) { dumpStackWithLocals(frames); } - throw new RuntimeException("local " + i + " value is " + - observed + ", expected " + expected); - } - - // Type - expected = Tester.LOCAL_TYPES[i]; - observed = type(locals[i]); - if (expected != null /* skip nulls in golden values */ && - !expected.equals(observed)) { - System.err.println("Local type mismatch:"); - if (!debug) { dumpStackWithLocals(frames); } - throw new RuntimeException("local " + i + " type is " + - observed + ", expected " + expected); - } - } - } - ); + dumpFramesIfDebug(frames); + try { + Stream.of(frames) + .filter(f -> KnownLocalsTester.TEST_METHODS.contains(f.getMethodName())) + .forEach(LocalsAndOperands::checkFrameLocals); + } catch (Exception e) { dumpFramesIfNotDebug(frames); throw e; } } /** - * Basic sanity check for locals and operands + * Check the locals in the given StackFrame against the expected values. */ - @Test(dataProvider = "provider") - public static void sanityCheck(StackFrame... frames) { - if (debug) { - System.out.println("Running sanityCheck"); - } - try { - Stream stream = Arrays.stream(frames); - if (debug) { - stream.forEach(LocalsAndOperands::printLocals); + private static void checkFrameLocals(StackFrame f) { + Object[] expectedArray = KnownLocalsTester.LOCAL_VALUES; + Object[] locals = invokeGetLocals(f); + + for (int i = 0; i < locals.length; i++) { + Object expected = expectedArray[i]; + Object observed = locals[i]; + + if (expected == null) { /* skip nulls in golden values */ + continue; + } else if (expected instanceof KnownLocalsTester.TwoSlotValue) { + // confirm integrity of expected values + assertEquals(expectedArray[i+1], null, + "Malformed array of expected values - slot after TwoSlotValue should be null"); + assertLongIsInSlots(locals[i], locals[i+1], + ((KnownLocalsTester.TwoSlotValue)expected).value); + i++; // skip following slot + } else if (primitiveSlotClass.isInstance(observed)) { // single slot primitive + assertTrue(primitiveValueEquals(observed, expected), + "Local value mismatch: local " + i + " value is " + + observed + ", expected " + expected); + } else if (expected instanceof Class) { + assertTrue(((Class)expected).isInstance(observed), + "Local value mismatch: local " + i + " expected instancof " + + expected + " but got " + observed); + } else if (expected instanceof String) { + assertEquals(expected, observed, "Local value mismatch: local " + + i + " value is " + observed + ", expected " + expected); } else { - System.out.println(stream.count() + " frames"); + throw new RuntimeException("Unrecognized expected local value " + + i + ": " + expected); } - } catch (Throwable t) { - dumpStackWithLocals(frames); - throw t; } } /** * Sanity check for locals and operands, including testng/jtreg frames + * using all StackWalker options. */ - @Test(dataProvider = "unfilteredProvider") - public static void unfilteredSanityCheck(StackFrame... frames) { + @Test + public synchronized void fullStackSanityCheck() throws Throwable { if (debug) { - System.out.println("Running unfilteredSanityCheck"); + System.out.println("Running fullStackSanityCheck"); } - try { - Stream stream = Arrays.stream(frames); + StackWalker sw = (StackWalker) getExtendedWalker.invoke(null, + EnumSet.of(SHOW_HIDDEN_FRAMES, SHOW_REFLECT_FRAMES, + RETAIN_CLASS_REFERENCE)); + sw.forEach(f -> { if (debug) { - stream.forEach(f -> { System.out.println(f + ": " + - invokeGetLocals(f).length + " locals"); } ); + printLocals(f); } else { - System.out.println(stream.count() + " frames"); + try { + System.out.println(" " + f + ": " + + ((Object[]) getLocals.invoke(f)).length + " locals, " + + ((Object[]) getOperands.invoke(f)).length + " operands, " + + ((Object[]) getMonitors.invoke(f)).length + " monitors"); + } catch (IllegalAccessException|InvocationTargetException t) { + throw new RuntimeException(t); + } } - } catch (Throwable t) { - dumpStackWithLocals(frames); - throw t; - } + }); } /** * Test that LiveStackFrames are not provided with the default StackWalker * options. */ - @Test(dataProvider = "noLocalsProvider") - public static void withoutLocalsAndOperands(StackFrame... frames) { - for (StackFrame frame : frames) { - if (liveStackFrameClass.isInstance(frame)) { - throw new RuntimeException("should not be LiveStackFrame"); - } - } + @Test + public static void noLocalsSanityCheck() { + StackWalker sw = StackWalker.getInstance(); + sw.forEach(f -> { + assertFalse(liveStackFrameClass.isInstance(f), + "should not be LiveStackFrame"); + }); } - static class Tester { + /** + * Class stack-walking methods with a known set of methods and local variables. + */ + static class KnownLocalsTester { private StackWalker walker; - private boolean filter = true; // Filter out testng/jtreg/etc frames? - Tester() { + KnownLocalsTester() { this.walker = extendedWalker; } - Tester(StackWalker walker, boolean filter) { - this.walker = walker; - this.filter = filter; - } - /** * Perform stackwalk without keeping local variables alive and return an * array of the collected StackFrames */ - private synchronized StackFrame[] testLocals() { + private synchronized StackFrame[] testLocalsUnused() { // Unused local variables will become dead - int x = 10; - char c = 'z'; + int x = 0xA; + char c = 'z'; // 0x7A String hi = "himom"; - long l = 1000000L; - double d = 3.1415926; + long l = 0x3FF00000000L + 0xFFFFL; + double d = Math.PI; - if (filter) { - return walker.walk(s -> s.filter(f -> TEST_METHODS.contains(f - .getMethodName())).collect(Collectors.toList())) - .toArray(new StackFrame[0]); - } else { - return walker.walk(s -> s.collect(Collectors.toList())) - .toArray(new StackFrame[0]); - } + return walker.walk(s -> + s.filter(f -> TEST_METHODS.contains(f.getMethodName())) + .toArray(StackFrame[]::new) + ); } /** @@ -264,64 +262,153 @@ public class LocalsAndOperands { * the collected StackFrames */ private synchronized StackFrame[] testLocalsKeepAlive() { - int x = 10; - char c = 'z'; + int x = 0xA; + char c = 'z'; // 0x7A String hi = "himom"; - long l = 1000000L; - double d = 3.1415926; + long l = 0x3FF00000000L + 0xFFFFL; + double d = Math.PI; - List frames; - if (filter) { - frames = walker.walk(s -> s.filter(f -> TEST_METHODS.contains(f - .getMethodName())).collect(Collectors.toList())); - } else { - frames = walker.walk(s -> s.collect(Collectors.toList())); - } + StackFrame[] frames = walker.walk(s -> + s.filter(f -> TEST_METHODS.contains(f.getMethodName())) + .toArray(StackFrame[]::new) + ); // Use local variables so they stay alive - System.out.println("Stayin' alive: "+x+" "+c+" "+hi+" "+l+" "+d); - return frames.toArray(new StackFrame[0]); // FIXME: convert to Array here + System.out.println("Stayin' alive: "+this+" "+x+" "+c+" "+hi+" "+l+" "+d); + return frames; } - // Expected values for locals in testLocals() & testLocalsKeepAlive() - // TODO: use real values instead of Strings, rebuild doubles & floats, etc - private final static String[] LOCAL_VALUES = new String[] { - null, // skip, LocalsAndOperands$Tester@XXX identity is different each run - "10", - "122", + /** + * Perform stackwalk, keeping method arguments alive, and return a list of + * the collected StackFrames + */ + private synchronized StackFrame[] testLocalsKeepAliveArgs(int x, char c, + String hi, long l, + double d) { + StackFrame[] frames = walker.walk(s -> + s.filter(f -> TEST_METHODS.contains(f.getMethodName())) + .toArray(StackFrame[]::new) + ); + + // Use local variables so they stay alive + System.out.println("Stayin' alive: "+this+" "+x+" "+c+" "+hi+" "+l+" "+d); + return frames; + } + + // An expected two-slot local (i.e. long or double) + static class TwoSlotValue { + public long value; + public TwoSlotValue(long value) { this.value = value; } + } + + // Expected values for locals in KnownLocalsTester.testLocals* methods + private final static Object[] LOCAL_VALUES = new Object[] { + LocalsAndOperands.KnownLocalsTester.class, + Integer.valueOf(0xA), + Integer.valueOf(0x7A), "himom", - "0", - null, // skip, fix in 8156073 - null, // skip, fix in 8156073 - null, // skip, fix in 8156073 - "0" + new TwoSlotValue(0x3FF00000000L + 0xFFFFL), + null, // 2nd slot + new TwoSlotValue(Double.doubleToRawLongBits(Math.PI)), + null, // 2nd slot + Integer.valueOf(0) }; - // Expected types for locals in testLocals() & testLocalsKeepAlive() - // TODO: use real types - private final static String[] LOCAL_TYPES = new String[] { - null, // skip - "I", - "I", - "java.lang.String", - "I", - "I", - "I", - "I", - "I" - }; - - final static Map NUM_LOCALS = Map.of("testLocals", 8, - "testLocalsKeepAlive", - LOCAL_VALUES.length); - private final static Collection TEST_METHODS = NUM_LOCALS.keySet(); + private final static List TEST_METHODS = + List.of("testLocalsUnused", + "testLocalsKeepAlive", + "testLocalsKeepAliveArgs"); } + /* Simpler tests of long & double arguments */ + + @Test + public static void testUsedLongArg() throws Exception { + usedLong(LOWER_LONG_VAL); + usedLong(UPPER_LONG_VAL); + usedLong(NEG_LONG_VAL); + } + + private static void usedLong(long longArg) throws Exception { + StackFrame[] frames = extendedWalker.walk(s -> + s.filter(f -> "usedLong".equals(f.getMethodName())) + .toArray(StackFrame[]::new) + ); + try { + dumpFramesIfDebug(frames); + + Object[] locals = (Object[]) getLocals.invoke(frames[0]); + assertLongIsInSlots(locals[0], locals[1], longArg); + System.out.println("Stayin' alive: " + longArg); + } catch (Exception t) { + dumpFramesIfNotDebug(frames); + throw t; + } + } + + @Test + public static void testUnusedLongArg() throws Exception { + if (testUnused) { + unusedLong(NEG_LONG_VAL); + } + } + + private static void unusedLong(long longArg) throws Exception { + StackFrame[] frames = extendedWalker.walk(s -> + s.filter(f -> "unusedLong".equals(f.getMethodName())) + .toArray(StackFrame[]::new) + ); + try { + dumpFramesIfDebug(frames); + + final Object[] locals = (Object[]) getLocals.invoke(frames[0]); + assertLongIsInSlots(locals[0], locals[1], NEG_LONG_VAL); + } catch (Exception t) { + dumpFramesIfNotDebug(frames); + throw t; + } + } + + @Test + public static void testUsedDoubleArg() throws Exception { + usedDouble(LOWER_DOUBLE_VAL); + usedDouble(UPPER_DOUBLE_VAL); + } + + private static void usedDouble(double doubleArg) throws Exception { + StackFrame[] frames = extendedWalker.walk(s -> + s.filter(f -> "usedDouble".equals(f.getMethodName())) + .toArray(StackFrame[]::new) + ); + try { + dumpFramesIfDebug(frames); + + Object[] locals = (Object[]) getLocals.invoke(frames[0]); + assertDoubleIsInSlots(locals[0], locals[1], doubleArg); + System.out.println("Stayin' alive: " + doubleArg); + } catch (Exception t) { + dumpFramesIfNotDebug(frames); + throw t; + } + } + + /******************* + * Utility Methods * + *******************/ + /** * Print stack trace with locals */ public static void dumpStackWithLocals(StackFrame...frames) { - Arrays.stream(frames).forEach(LocalsAndOperands::printLocals); + Stream.of(frames).forEach(LocalsAndOperands::printLocals); + } + + public static void dumpFramesIfDebug(StackFrame...frames) { + if (debug) { dumpStackWithLocals(frames); } + } + + public static void dumpFramesIfNotDebug(StackFrame...frames) { + if (!debug) { dumpStackWithLocals(frames); } } /** @@ -329,10 +416,21 @@ public class LocalsAndOperands { */ public static void printLocals(StackWalker.StackFrame frame) { try { - System.out.println(frame); + System.out.println("Locals for: " + frame); Object[] locals = (Object[]) getLocals.invoke(frame); for (int i = 0; i < locals.length; i++) { - System.out.format(" local %d: %s type %s\n", i, locals[i], type(locals[i])); + String localStr = null; + + if (primitiveSlot64Class.isInstance(locals[i])) { + localStr = String.format("0x%X", + (Long)primitiveLongValue.invoke(locals[i])); + } else if (primitiveSlot32Class.isInstance(locals[i])) { + localStr = String.format("0x%X", + (Integer)primitiveIntValue.invoke(locals[i])); + } else if (locals[i] != null) { + localStr = locals[i].toString(); + } + System.out.format(" local %d: %s type %s\n", i, localStr, type(locals[i])); } Object[] operands = (Object[]) getOperands.invoke(frame); @@ -352,12 +450,87 @@ public class LocalsAndOperands { try { if (o == null) { return "null"; - } else if (primitiveValueClass.isInstance(o)) { - char c = (char)primitiveType.invoke(o); - return String.valueOf(c); + } else if (primitiveSlotClass.isInstance(o)) { + int s = (int)primitiveSize.invoke(o); + return s + "-byte primitive"; } else { return o.getClass().getName(); } } catch(Exception e) { throw new RuntimeException(e); } } + + /* + * Check if the PrimitiveValue "primVal" contains the specified value, + * either a Long or an Integer. + */ + static boolean primitiveValueEquals(Object primVal, Object expectedVal) { + try { + if (expectedVal instanceof Long) { + assertFalse(is32bit); + assertTrue(primitiveSlot64Class.isInstance(primVal)); + assertTrue(8 == (int)primitiveSize.invoke(primVal)); + return Objects.equals(primitiveLongValue.invoke(primVal), expectedVal); + } else if (expectedVal instanceof Integer) { + int expectedInt = (Integer)expectedVal; + if (is32bit) { + assertTrue(primitiveSlot32Class.isInstance(primVal), + "expected a PrimitiveSlot32 on 32-bit VM"); + assertTrue(4 == (int)primitiveSize.invoke(primVal)); + return expectedInt == (int)primitiveIntValue.invoke(primVal); + } else { + assertTrue(primitiveSlot64Class.isInstance(primVal), + "expected a PrimitiveSlot64 on 64-bit VM"); + assertTrue(8 == (int)primitiveSize.invoke(primVal)); + // Look for int expectedVal in high- or low-order 32 bits + long primValLong = (long)primitiveLongValue.invoke(primVal); + return (int)(primValLong & 0x00000000FFFFFFFFL) == expectedInt || + (int)(primValLong >>> 32) == expectedInt; + } + } else { + throw new RuntimeException("Called with non-Integer/Long: " + expectedVal); + } + } catch (IllegalAccessException|InvocationTargetException e) { + throw new RuntimeException(e); + } + + } + + /* + * Assert that the expected 2-slot long value is stored somewhere in the + * pair of slots. + * Throw exception if long value isn't in the two slots given. + * Accounts for 32 vs 64 bit, but is lax on endianness (accepts either) + */ + static void assertLongIsInSlots(Object primVal0, Object primVal1, long expected) { + try { + if (is32bit) { + int upper = (int)(expected & 0xFFFFFFFFL); + int lower = (int)(expected >> 32); + + if (!((primitiveValueEquals(primVal0, upper) && + primitiveValueEquals(primVal1, lower)) || + (primitiveValueEquals(primVal0, lower) && + primitiveValueEquals(primVal1, upper)))) { + throw new RuntimeException(String.format("0x%X and 0x%X of 0x%016X not found in 0x%X and 0x%X", + upper, lower, expected, + (int)primitiveIntValue.invoke(primVal0), + (int)primitiveIntValue.invoke(primVal1))); + } + } else { + if (!(primitiveValueEquals(primVal0, expected) || + primitiveValueEquals(primVal1, expected))) { + throw new RuntimeException(String.format("0x%016X not found in 0x%016X or 0x%016X", + expected, + (long)primitiveLongValue.invoke(primVal0), + (long)primitiveLongValue.invoke(primVal1))); + } + } + } catch (IllegalAccessException|InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + static void assertDoubleIsInSlots(Object primVal0, Object primVal1, double expected) { + assertLongIsInSlots(primVal0, primVal1, Double.doubleToRawLongBits(expected)); + } } diff --git a/jdk/test/java/lang/StackWalker/LocalsCrash.java b/jdk/test/java/lang/StackWalker/LocalsCrash.java deleted file mode 100644 index 178e07c34f3..00000000000 --- a/jdk/test/java/lang/StackWalker/LocalsCrash.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 8147039 - * @summary Test for -Xcomp crash that happened before 8147039 fix - * @modules java.base/java.lang:open - * @run testng/othervm -Xcomp LocalsCrash - */ - -import org.testng.annotations.*; -import java.lang.reflect.*; -import java.util.List; -import java.util.stream.Collectors; - -public class LocalsCrash { - static Class liveStackFrameClass; - static Method getStackWalker; - - static { - try { - liveStackFrameClass = Class.forName("java.lang.LiveStackFrame"); - getStackWalker = liveStackFrameClass.getMethod("getStackWalker"); - getStackWalker.setAccessible(true); - } catch (Throwable t) { throw new RuntimeException(t); } - } - - private StackWalker walker; - - LocalsCrash() { - try { - walker = (StackWalker) getStackWalker.invoke(null); - } catch (Exception e) { throw new RuntimeException(e); } - } - - @Test - public void test00() { doStackWalk(); } - - @Test - public void test01() { doStackWalk(); } - - private synchronized List doStackWalk() { - try { - // Unused local variables will become dead - int x = 10; - char c = 'z'; - String hi = "himom"; - long l = 1000000L; - double d = 3.1415926; - - return walker.walk(s -> s.collect(Collectors.toList())); - } catch (Exception e) { throw new RuntimeException(e); } - } -} diff --git a/jdk/test/java/lang/StackWalker/ReflectionFrames.java b/jdk/test/java/lang/StackWalker/ReflectionFrames.java new file mode 100644 index 00000000000..eacc55fe92b --- /dev/null +++ b/jdk/test/java/lang/StackWalker/ReflectionFrames.java @@ -0,0 +1,842 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8173898 + * @summary Basic test for checking filtering of reflection frames + * @run testng ReflectionFrames + */ + +import java.lang.StackWalker.StackFrame; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.util.EnumSet; +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import static java.lang.StackWalker.Option.*; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class ReflectionFrames { + final static boolean verbose = false; + + /** + * This test invokes new StackInspector() directly from + * the caller StackInspector.Caller.create method. + * It checks that the caller is StackInspector.Caller. + * It also checks the expected frames collected + * by walking the stack from the default StackInspector() + * constructor. + * This is done twice, once using a default StackWalker + * that hides reflection frames, once using a StackWalker + * configured to show reflection frames. + */ + @Test + public static void testNewStackInspector() throws Exception { + // Sets the default walker which hides reflection + // frames. + StackInspector.walker.set(StackInspector.walkerHide); + + // Calls the StackInspector.create method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The create method invokes new StackInspector() directly. + // No reflection frame should appear. + System.out.println("testNewStackInspector: create"); + + StackInspector obj = ((StackInspector)StackInspector.Caller.class + .getMethod("create", How.class) + .invoke(null, How.NEW)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + ReflectionFrames.class.getName() + +"::testNewStackInspector")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertEquals(obj.filtered, 0); + + // Calls the StackInspector.reflect method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The reflect method invokes the create method through + // reflection. + // The create method invokes new StackInspector() directly. + // No reflection frame should appear. + System.out.println("testNewStackInspector: reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("reflect", How.class) + .invoke(null, How.NEW)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + StackInspector.Caller.class.getName() + +"::reflect", + ReflectionFrames.class.getName() + +"::testNewStackInspector")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertEquals(obj.filtered, 0); + + // Calls the StackInspector.handle method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The handle method invokes the create method using + // a MethodHandle. + // The create method invokes new StackInspector() directly. + // No reflection frame should appear. + System.out.println("testNewStackInspector: handle"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("handle", How.class) + .invoke(null, How.NEW)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + StackInspector.Caller.class.getName() + +"::handle", + ReflectionFrames.class.getName() + +"::testNewStackInspector")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertEquals(obj.filtered, 0); + + // Sets a non-default walker configured to show + // reflection frames + StackInspector.walker.set(StackInspector.walkerShow); + + // Calls the StackInspector.create method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The create method invokes new StackInspector() directly. + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testNewStackInspector: create: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("create", How.class) + .invoke(null, How.NEW)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testNewStackInspector")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertNotEquals(obj.filtered, 0); + + // Calls the StackInspector.reflect method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The reflect method invokes the create method through + // reflection. + // The create method invokes new StackInspector() directly. + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testNewStackInspector: reflect: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("reflect", How.class) + .invoke(null, How.NEW)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + Method.class.getName() + +"::invoke", + StackInspector.Caller.class.getName() + +"::reflect", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testNewStackInspector")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertNotEquals(obj.filtered, 0); + + // Calls the StackInspector.handle method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The handle method invokes the create method using + // MethodHandle. + // The create method invokes new StackInspector() directly. + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testNewStackInspector: handle: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("handle", How.class) + .invoke(null, How.NEW)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + // MethodHandle::invoke remains hidden + StackInspector.Caller.class.getName() + +"::handle", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testNewStackInspector")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertNotEquals(obj.filtered, 0); + } + + /** + * This test invokes Constructor.newInstance() from + * the caller StackInspector.Caller.create method. + * It checks that the caller is StackInspector.Caller. + * It also checks the expected frames collected + * by walking the stack from the default StackInspector() + * constructor. + * This is done twice, once using a default StackWalker + * that hides reflection frames, once using a StackWalker + * configured to show reflection frames. + */ + @Test + public static void testConstructor() throws Exception { + // Sets the default walker which hides reflection + // frames. + StackInspector.walker.set(StackInspector.walkerHide); + + // Calls the StackInspector.create method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The create method invokes Constructor.newInstance(). + // No reflection frame should appear. + System.out.println("testConstructor: create"); + + StackInspector obj = ((StackInspector)StackInspector.Caller.class + .getMethod("create", How.class) + .invoke(null, How.CONSTRUCTOR)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + ReflectionFrames.class.getName() + +"::testConstructor")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertEquals(obj.filtered, 0); + + // Calls the StackInspector.reflect method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The reflect method invokes the create method through + // reflection. + // The create method invokes Constructor.newInstance(). + // No reflection frame should appear. + System.out.println("testConstructor: reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("reflect", How.class) + .invoke(null, How.CONSTRUCTOR)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + StackInspector.Caller.class.getName() + +"::reflect", + ReflectionFrames.class.getName() + +"::testConstructor")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertEquals(obj.filtered, 0); + + // Calls the StackInspector.handle method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The handle method invokes the create method using + // MethodHandle. + // The create method invokes Constructor.newInstance(). + // No reflection frame should appear. + System.out.println("testConstructor: handle"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("handle", How.class) + .invoke(null, How.CONSTRUCTOR)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + StackInspector.Caller.class.getName() + +"::create", + StackInspector.Caller.class.getName() + +"::handle", + ReflectionFrames.class.getName() + +"::testConstructor")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertEquals(obj.filtered, 0); + + // Sets a non-default walker configured to show + // reflection frames + StackInspector.walker.set(StackInspector.walkerShow); + + // Calls the StackInspector.create method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The create method invokes Constructor.newInstance(). + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testConstructor: create: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("create", How.class) + .invoke(null, How.CONSTRUCTOR)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Constructor.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testConstructor")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertNotEquals(obj.filtered, 0); + + // Calls the StackInspector.reflect method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The reflect method invokes the create method through + // reflection. + // The create method invokes Constructor.newInstance(). + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testConstructor: reflect: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("reflect", How.class) + .invoke(null, How.CONSTRUCTOR)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Constructor.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + Method.class.getName() + +"::invoke", + StackInspector.Caller.class.getName() + +"::reflect", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testConstructor")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertNotEquals(obj.filtered, 0); + + // Calls the StackInspector.handle method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The handle method invokes the create method using + // MethodHandle. + // The create method invokes Constructor.newInstance(). + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testConstructor: handle: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("handle", How.class) + .invoke(null, How.CONSTRUCTOR)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Constructor.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + // MethodHandle::invoke remains hidden + StackInspector.Caller.class.getName() + +"::handle", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testConstructor")); + assertEquals(obj.cls, StackInspector.Caller.class); + assertNotEquals(obj.filtered, 0); + } + + /** + * This test invokes StackInspector.class.newInstance() from + * the caller StackInspector.Caller.create method. Because + * Class.newInstance() is not considered as a + * reflection frame, the the caller returned by + * getCallerClass() should appear to be java.lang.Class + * and not StackInspector.Caller. + * It also checks the expected frames collected + * by walking the stack from the default StackInspector() + * constructor. + * This is done twice, once using a default StackWalker + * that hides reflection frames, once using a StackWalker + * configured to show reflection frames. + */ + @Test + public static void testNewInstance() throws Exception { + // Sets the default walker which hides reflection + // frames. + StackInspector.walker.set(StackInspector.walkerHide); + + // Calls the StackInspector.create method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The create method invokes StackInspector.class.newInstance(). + // No reflection frame should appear, except + // Class::newInstance which is not considered as + // a reflection frame. + System.out.println("testNewInstance: create"); + + StackInspector obj = ((StackInspector)StackInspector.Caller.class + .getMethod("create", How.class) + .invoke(null, How.CLASS)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Class.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + ReflectionFrames.class.getName() + +"::testNewInstance")); + // Because Class.newInstance is not filtered, then the + // caller is Class.class + assertEquals(obj.cls, Class.class); + assertEquals(obj.filtered, 0); + + // Calls the StackInspector.reflect method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The reflect method invokes the create method through + // reflection. + // The create method invokes StackInspector.class.newInstance(). + // No reflection frame should appear, except + // Class::newInstance which is not considered as + // a reflection frame. + System.out.println("testNewInstance: reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("reflect", How.class) + .invoke(null, How.CLASS)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Class.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + StackInspector.Caller.class.getName() + +"::reflect", + ReflectionFrames.class.getName() + +"::testNewInstance")); + + // Because Class.newInstance is not filtered, then the + // caller is Class.class + assertEquals(obj.cls, Class.class); + assertEquals(obj.filtered, 0); + + // Calls the StackInspector.handle method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The handle method invokes the create method using + // reflection. + // The create method invokes StackInspector.class.newInstance(). + // No reflection frame should appear, except + // Class::newInstance which is not considered as + // a reflection frame. + System.out.println("testNewInstance: handle"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("handle", How.class) + .invoke(null, How.CLASS)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Class.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + StackInspector.Caller.class.getName() + +"::handle", + ReflectionFrames.class.getName() + +"::testNewInstance")); + + // Because Class.newInstance is not filtered, then the + // caller is Class.class + assertEquals(obj.cls, Class.class); + assertEquals(obj.filtered, 0); + + // Sets a non-default walker configured to show + // reflection frames + StackInspector.walker.set(StackInspector.walkerShow); + + // Calls the StackInspector.create method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The create method invokes StackInspector.class.newInstance(). + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testNewInstance: create: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("create", How.class) + .invoke(null, How.CLASS)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Constructor.class.getName() + +"::newInstance", + Class.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testNewInstance")); + // Because Class.newInstance is not filtered, then the + // caller is Class.class + assertEquals(obj.cls, Class.class); + assertNotEquals(obj.filtered, 0); + + // Calls the StackInspector.reflect method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The reflect method invokes the create method through + // reflection. + // The create method invokes StackInspector.class.newInstance(). + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testNewInstance: reflect: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("reflect", How.class) + .invoke(null, How.CLASS)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Constructor.class.getName() + +"::newInstance", + Class.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + Method.class.getName() + +"::invoke", + StackInspector.Caller.class.getName() + +"::reflect", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testNewInstance")); + + // Because Class.newInstance is not filtered, then the + // caller is Class.class + assertEquals(obj.cls, Class.class); + assertNotEquals(obj.filtered, 0); + + // Calls the StackInspector.handle method through reflection + // and check the frames collected in the StackInspector + // default constructor. + // The handle method invokes the create method using + // MethodHandle. + // The create method invokes StackInspector.class.newInstance(). + // We should see all reflection frames, except the + // jdk.internal.reflect frames which we are filtering + // out in StackInspector::filter. + System.out.println("testNewInstance: handle: show reflect"); + + obj = ((StackInspector)StackInspector.Caller.class + .getMethod("handle", How.class) + .invoke(null, How.CLASS)); + assertEquals(obj.collectedFrames, + List.of(StackInspector.class.getName() + +"::", + Constructor.class.getName() + +"::newInstance", + Class.class.getName() + +"::newInstance", + StackInspector.Caller.class.getName() + +"::create", + // MethodHandle::invoke remains hidden + StackInspector.Caller.class.getName() + +"::handle", + Method.class.getName() + +"::invoke", + ReflectionFrames.class.getName() + +"::testNewInstance")); + + // Because Class.newInstance is not filtered, then the + // caller is Class.class + assertEquals(obj.cls, Class.class); + assertNotEquals(obj.filtered, 0); + } + + @Test + public static void testGetCaller() throws Exception { + // Sets the default walker which hides reflection + // frames. + StackInspector.walker.set(StackInspector.walkerHide); + + assertEquals(StackInspector.getCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("getCaller").invoke(null), + ReflectionFrames.class); + + // Sets a non-default walker configured to show + // reflection frames + StackInspector.walker.set(StackInspector.walkerShow); + + assertEquals(StackInspector.getCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("getCaller").invoke(null), + ReflectionFrames.class); + } + + @Test + public static void testReflectCaller() throws Exception { + // Sets the default walker which hides reflection + // frames. + StackInspector.walker.set(StackInspector.walkerHide); + + assertEquals(StackInspector.reflectCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("reflectCaller").invoke(null), + ReflectionFrames.class); + + // Sets a non-default walker configured to show + // reflection frames + StackInspector.walker.set(StackInspector.walkerShow); + + assertEquals(StackInspector.reflectCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("reflectCaller").invoke(null), + ReflectionFrames.class); + } + + @Test + public static void testSupplyCaller() throws Exception { + // Sets the default walker which hides reflection + // frames. + StackInspector.walker.set(StackInspector.walkerHide); + + assertEquals(StackInspector.supplyCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("supplyCaller").invoke(null), + ReflectionFrames.class); + + // Sets a non-default walker configured to show + // reflection frames + StackInspector.walker.set(StackInspector.walkerShow); + + assertEquals(StackInspector.supplyCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("supplyCaller").invoke(null), + ReflectionFrames.class); + } + + @Test + public static void testHandleCaller() throws Exception { + // Sets the default walker which hides reflection + // frames. + StackInspector.walker.set(StackInspector.walkerHide); + + assertEquals(StackInspector.handleCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("handleCaller").invoke(null), + ReflectionFrames.class); + + // Sets a non-default walker configured to show + // reflection frames + StackInspector.walker.set(StackInspector.walkerShow); + + assertEquals(StackInspector.handleCaller(), ReflectionFrames.class); + assertEquals(StackInspector.class.getMethod("handleCaller").invoke(null), + ReflectionFrames.class); + } + + static enum How { NEW, CONSTRUCTOR, CLASS}; + + /** + * An object that collect stack frames by walking the stack + * (and calling getCallerClass()) from within its constructor. + * For the purpose of this test, StackInspector objects are + * always created from the nested StackInspector.Caller class, + * which should therefore appear as the caller of the + * StackInspector constructor. + */ + static class StackInspector { + static final StackWalker walkerHide = + StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + static final StackWalker walkerShow = + StackWalker.getInstance(EnumSet.of( + StackWalker.Option.RETAIN_CLASS_REFERENCE, + StackWalker.Option.SHOW_REFLECT_FRAMES)); + final static ThreadLocal walker = new ThreadLocal<>() { + protected StackWalker initialValue() { + return walkerHide; + } + }; + + List collectedFrames; + Class cls = null; + boolean stop; + int filtered; + final boolean filterImplFrames; + + public StackInspector() { + stop = false; + // if reflection frames are not hidden, we want to + // filter implementation frames before collecting + // to avoid depending on internal details. + filterImplFrames = walker.get() == walkerShow; + collectedFrames = walker.get().walk(this::parse); + cls = walker.get().getCallerClass(); + } + + public List collectedFrames() { + return collectedFrames; + } + + // The takeWhile method arrange for stopping frame collection + // as soon as a frame from ReflectionFrames.class is reached. + // The first such frame encountered is still included in the + // collected frames, but collection stops right after. + // This makes it possible to filter out anything above the + // the test method frame, such as frames from the test + // framework. + public boolean takeWhile(StackFrame f) { + if (stop) return false; + if (verbose) System.out.println(" " + f); + stop = stop || f.getDeclaringClass() == ReflectionFrames.class; + return true; + } + + // filter out implementation frames to avoid depending + // on implementation details. If present, Class::newInstance, + // Method::invoke and Constructor::newInstance will + // still appear in the collected frames, which is + // sufficient for the purpose of the test. + // In the case where the StackWalker itself is supposed to + // filter the reflection frames, then this filter will always + // return true. This way, if such a reflection frame appears when + // it sjould have been filtered by StackWalker, it will make the + // test fail. + public boolean filter(StackFrame f) { + if (filterImplFrames && + f.getClassName().startsWith("jdk.internal.reflect.")) { + filtered++; + return false; + } + if (!verbose) System.out.println(" " + f); + return true; + } + + public String frame(StackFrame f) { + return f.getClassName() + "::" + f.getMethodName(); + } + + List parse(Stream s) { + return s.takeWhile(this::takeWhile) + .filter(this::filter) + .map(this::frame) + .collect(Collectors.toList()); + } + + /** + * The Caller class is used to create instances of + * StackInspector, either direcltly, or throug reflection. + */ + public static class Caller { + public static StackInspector create(How how) throws Exception { + switch(how) { + case NEW: return new StackInspector(); + case CONSTRUCTOR: return StackInspector.class + .getConstructor().newInstance(); + case CLASS: return StackInspector.class.newInstance(); + default: throw new AssertionError(String.valueOf(how)); + } + } + public static StackInspector reflect(How how) throws Exception { + return (StackInspector) Caller.class.getMethod("create", How.class) + .invoke(null, how); + } + public static StackInspector handle(How how) throws Exception { + Lookup lookup = MethodHandles.lookup(); + MethodHandle mh = lookup.findStatic(Caller.class, "create", + MethodType.methodType(StackInspector.class, How.class)); + try { + return (StackInspector) mh.invoke(how); + } catch (Error | Exception x) { + throw x; + } catch(Throwable t) { + throw new AssertionError(t); + } + } + } + + public static Class getCaller() throws Exception { + return walker.get().getCallerClass(); + } + + public static Class reflectCaller() throws Exception { + return (Class)StackWalker.class.getMethod("getCallerClass") + .invoke(walker.get()); + } + + public static Class supplyCaller() throws Exception { + return ((Supplier>)StackInspector.walker.get()::getCallerClass).get(); + } + + public static Class handleCaller() throws Exception { + Lookup lookup = MethodHandles.lookup(); + MethodHandle mh = lookup.findVirtual(StackWalker.class, "getCallerClass", + MethodType.methodType(Class.class)); + try { + return (Class) mh.invoke(walker.get()); + } catch (Error | Exception x) { + throw x; + } catch(Throwable t) { + throw new AssertionError(t); + } + } + } +} diff --git a/jdk/test/java/lang/invoke/AccessControlTest.java b/jdk/test/java/lang/invoke/AccessControlTest.java index 57cec50b2ec..616ba798ba6 100644 --- a/jdk/test/java/lang/invoke/AccessControlTest.java +++ b/jdk/test/java/lang/invoke/AccessControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,6 +118,8 @@ public class AccessControlTest { suffix = "/noaccess"; else if (lookupModes == PUBLIC) suffix = "/public"; + else if (lookupModes == (PUBLIC|UNCONDITIONAL)) + suffix = "/publicLookup"; else if (lookupModes == (PUBLIC|MODULE)) suffix = "/module"; else if (lookupModes == (PUBLIC|MODULE|PACKAGE)) @@ -140,23 +142,24 @@ public class AccessControlTest { * [A2] However, the resulting {@code Lookup} object is guaranteed * to have no more access capabilities than the original. * In particular, access capabilities can be lost as follows:

        - *
      • [A3] If the new lookup class differs from the old one, - * protected members will not be accessible by virtue of inheritance. + *
      • [A3] If the old lookup class is in a named module, and the new + * lookup class is in a different module {@code M}, then no members, not + * even public members in {@code M}'s exported packages, will be accessible. + * The exception to this is when this lookup is publicLookup, in which case + * public access is not lost. + *
      • [A4] If the old lookup class is in an unnamed module, and the new + * lookup class is a different module then module access is lost. + *
      • [A5] If the new lookup class differs from the old one then UNCONDITIONAL + * is lost. If the new lookup class is not within the same package member as the + * old one, protected members will not be accessible by virtue of inheritance. * (Protected members may continue to be accessible because of package sharing.) - *
      • [A4] If the new lookup class is in a different package - * than the old one, protected and default (package) members will not be accessible. - *
      • [A5] If the new lookup class is not within the same package member + *
      • [A6] If the new lookup class is in a different package than the old one, + * protected and default (package) members will not be accessible. + *
      • [A7] If the new lookup class is not within the same package member * as the old one, private members will not be accessible. - *
      • [A6] If the new lookup class is not accessible to the old lookup class, - * using the original access modes, + *
      • [A8] If the new lookup class is not accessible to the old lookup class, * then no members, not even public members, will be accessible. - *
      • [A7] If the new lookup class for this {@code Lookup} is in the unnamed module, - * and the new lookup class is in a named module {@code M}, then no members in - * {@code M}'s non-exported packages will be accessible. - *
      • [A8] If the lookup for this {@code Lookup} is in a named module, and the - * new lookup class is in a different module, then no members, not even - * public members in {@code M}'s exported packages, will be accessible. - * [A8] (In all other cases, public members will continue to be accessible.) + *
      • [A9] (In all other cases, public members will continue to be accessible.) *
      * Other than the above cases, the new lookup will have the same * access capabilities as the original. [A10] @@ -171,36 +174,35 @@ public class AccessControlTest { boolean sameModule = (c1.getModule() == c2.getModule()) || (!c1.getModule().isNamed() && !c2.getModule().isNamed()); boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() && - packagePrefix(c1).equals(packagePrefix(c2))); + c1.getPackageName().equals(c2.getPackageName())); boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2)); boolean sameClass = (c1 == c2); assert(samePackage || !sameTopLevel); assert(sameTopLevel || !sameClass); - boolean accessible = sameClass; // [A6] + boolean accessible = sameClass; if ((m1 & PACKAGE) != 0) accessible |= samePackage; if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0; if (!sameModule) { - if (c1.getModule().isNamed()) { - accessible = false; // [A8] + if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) { + accessible = false; // [A3] } else { - // Different module; loose MODULE and lower access. - changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A7] + changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A3] [A4] } } if (!accessible) { // Different package and no access to c2; lose all access. - changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A6] + changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A8] } if (!samePackage) { // Different package; loose PACKAGE and lower access. - changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4] + changed |= (PACKAGE|PRIVATE|PROTECTED); // [A6] } if (!sameTopLevel) { - // Different top-level class. Lose PRIVATE and lower access. - changed |= (PRIVATE|PROTECTED); // [A5] + // Different top-level class. Lose PRIVATE and PROTECTED access. + changed |= (PRIVATE|PROTECTED); // [A5] [A7] } if (!sameClass) { - changed |= (PROTECTED); // [A3] + changed |= (UNCONDITIONAL); // [A5] } else { assert(changed == 0); // [A10] (no deprivation if same class) } @@ -228,11 +230,10 @@ public class AccessControlTest { Class c1 = lookupClass(); Class c2 = m.getDeclaringClass(); - // if the lookup class is in a loose module with PUBLIC access then - // public members of public types in all unnamed modules can be accessed - if (isLooseModule(c1.getModule()) + // publicLookup has access to all public types/members of types in unnamed modules + if ((lookupModes & UNCONDITIONAL) != 0 && (lookupModes & PUBLIC) != 0 - && (!c2.getModule().isNamed()) + && !c2.getModule().isNamed() && Modifier.isPublic(c2.getModifiers()) && Modifier.isPublic(m.getModifiers())) return true; @@ -261,17 +262,12 @@ public class AccessControlTest { if (load && c2.getClassLoader() != null) { if (c1.getClassLoader() == null) { // not visible - return false; - } - if (c1 == publicLookup().lookupClass()) { - // not visible as lookup class is defined by child of the boot loader return false; } } - // if the lookup class is in a loose module with PUBLIC access then - // public types in all unnamed modules can be accessed - if (isLooseModule(c1.getModule()) + // publicLookup has access to all public types/members of types in unnamed modules + if ((lookupModes & UNCONDITIONAL) != 0 && (lookupModes & PUBLIC) != 0 && (!c2.getModule().isNamed()) && Modifier.isPublic(c2.getModifiers())) @@ -295,11 +291,6 @@ public class AccessControlTest { } return r; } - - private boolean isLooseModule(Module m) { - ClassLoader cl = new ClassLoader() { }; - return m.canRead(cl.getUnnamedModule()); - } } private static Class topLevelClass(Class cls) { @@ -311,14 +302,6 @@ public class AccessControlTest { return c; } - private static String packagePrefix(Class c) { - while (c.isArray()) c = c.getComponentType(); - String s = c.getName(); - assert(s.indexOf('/') < 0); - return s.substring(0, s.lastIndexOf('.')+1); - } - - private final TreeSet CASES = new TreeSet<>(); private final TreeMap> CASE_EDGES = new TreeMap<>(); private final ArrayList LOADERS = new ArrayList<>(); diff --git a/jdk/test/java/lang/invoke/DropLookupModeTest.java b/jdk/test/java/lang/invoke/DropLookupModeTest.java index be7d0a60e54..64cb99e15e7 100644 --- a/jdk/test/java/lang/invoke/DropLookupModeTest.java +++ b/jdk/test/java/lang/invoke/DropLookupModeTest.java @@ -65,6 +65,10 @@ public class DropLookupModeTest { lookup = fullPowerLookup.dropLookupMode(PUBLIC); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == 0); + + lookup = fullPowerLookup.dropLookupMode(UNCONDITIONAL); + assertTrue(lookup.lookupClass() == lc); + assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE)); } /** @@ -108,7 +112,7 @@ public class DropLookupModeTest { public void testPublicLookup() { final Lookup publicLookup = MethodHandles.publicLookup(); final Class lc = publicLookup.lookupClass(); - assertTrue(publicLookup.lookupModes() == PUBLIC); + assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); Lookup lookup = publicLookup.dropLookupMode(PRIVATE); assertTrue(lookup.lookupClass() == lc); @@ -129,6 +133,10 @@ public class DropLookupModeTest { lookup = publicLookup.dropLookupMode(PUBLIC); assertTrue(lookup.lookupClass() == lc); assertTrue(lookup.lookupModes() == 0); + + lookup = publicLookup.dropLookupMode(UNCONDITIONAL); + assertTrue(lookup.lookupClass() == lc); + assertTrue(lookup.lookupModes() == PUBLIC); } @DataProvider(name = "badInput") diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java index 5abe4eb2383..810351bae3e 100644 --- a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java @@ -23,7 +23,7 @@ /** * @test - * @build test/* m1/* m2/* m3/* + * @build test/* m1/* m2/* m3/* Unnamed * @run testng/othervm test/p.PrivateLookupInTests * @summary Unit tests for MethodHandles.privateLookupIn */ diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java new file mode 100644 index 00000000000..9bb0ff042a3 --- /dev/null +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +public class Unnamed { } diff --git a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java index 823ae8797b5..f2391743bd0 100644 --- a/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java +++ b/jdk/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,6 +126,26 @@ public class PrivateLookupInTests { Object obj = mh.invokeExact(); } + // test target class in unnamed module + public void testTargetClassInUnnamedModule() throws Throwable { + Class clazz = Class.forName("Unnamed"); + assertFalse(clazz.getModule().isNamed()); + + // thisModule does not read the unnamed module + Module thisModule = getClass().getModule(); + assertFalse(thisModule.canRead(clazz.getModule())); + try { + MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // thisModule reads the unnamed module + thisModule.addReads(clazz.getModule()); + Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup()); + assertTrue(lookup.lookupClass() == clazz); + assertTrue(lookup.hasPrivateAccess()); + } + // test does not read m2, m2 opens p2 to test @Test(expectedExceptions = {IllegalAccessException.class}) public void testCallerDoesNotRead() throws Throwable { diff --git a/jdk/test/java/lang/invoke/lambda/MetafactoryDescriptorTest.java b/jdk/test/java/lang/invoke/lambda/MetafactoryDescriptorTest.java new file mode 100644 index 00000000000..a22e5dac2df --- /dev/null +++ b/jdk/test/java/lang/invoke/lambda/MetafactoryDescriptorTest.java @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8035776 8173587 + * @summary metafactory should fail if instantiatedMethodType does not match sam/bridge descriptors + */ +import java.lang.invoke.*; +import java.util.*; + +public class MetafactoryDescriptorTest { + + static final MethodHandles.Lookup lookup = MethodHandles.lookup(); + + static MethodType mt(Class ret, Class... params) { + return MethodType.methodType(ret, params); + } + + public interface I {} + + public static class C { + public static void m_void(String arg) {} + public static boolean m_boolean(String arg) { return true; } + public static char m_char(String arg) { return 'x'; } + public static byte m_byte(String arg) { return 12; } + public static short m_short(String arg) { return 12; } + public static int m_int(String arg) { return 12; } + public static long m_long(String arg) { return 12; } + public static float m_float(String arg) { return 12; } + public static double m_double(String arg) { return 12; } + public static String m_String(String arg) { return ""; } + public static Integer m_Integer(String arg) { return 23; } + public static Object m_Object(String arg) { return new Object(); } + + public static String n_boolean(boolean arg) { return ""; } + public static String n_char(char arg) { return ""; } + public static String n_byte(byte arg) { return ""; } + public static String n_short(short arg) { return ""; } + public static String n_int(int arg) { return ""; } + public static String n_long(long arg) { return ""; } + public static String n_float(float arg) { return ""; } + public static String n_double(double arg) { return ""; } + public static String n_String(String arg) { return ""; } + public static String n_Integer(Integer arg) { return ""; } + public static String n_Object(Object arg) { return ""; } + + public static MethodHandle getM(Class c) { + try { + return lookup.findStatic(C.class, "m_" + c.getSimpleName(), mt(c, String.class)); + } + catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static MethodHandle getN(Class c) { + if (c == void.class) return null; + try { + return lookup.findStatic(C.class, "n_" + c.getSimpleName(), mt(String.class, c)); + } + catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + } + + public static void main(String... args) { + Class[] t = { void.class, boolean.class, char.class, + byte.class, short.class, int.class, long.class, float.class, double.class, + String.class, Integer.class, Object.class }; + + for (int i = 0; i < t.length; i++) { + MethodHandle m = C.getM(t[i]); + MethodHandle n = C.getN(t[i]); // null for void.class + for (int j = 0; j < t.length; j++) { + boolean correctRet = t[j].isAssignableFrom(t[i]) || conversions.contains(t[i], t[j]); + test(correctRet, m, mt(t[i], String.class), mt(t[j], String.class)); + testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class), + mt(t[j], Object.class)); + testBridge(correctRet, m, mt(t[i], String.class), mt(t[i], String.class), + mt(t[i], CharSequence.class), mt(t[j], Object.class)); + + if (t[i] != void.class && t[j] != void.class) { + boolean correctParam = t[j].isAssignableFrom(t[i]); + test(correctParam, n, mt(String.class, t[i]), mt(String.class, t[j])); + testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]), + mt(Object.class, t[j])); + testBridge(correctParam, n, mt(String.class, t[i]), mt(String.class, t[i]), + mt(CharSequence.class, t[i]), mt(Object.class, t[j])); + } + + } + } + } + + static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) { + tryMetafactory(correct, mh, instMT, samMT); + tryAltMetafactory(correct, mh, instMT, samMT); + } + + static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) { + tryAltMetafactory(correct, mh, instMT, samMT, bridgeMTs); + } + + static void tryMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) { + try { + LambdaMetafactory.metafactory(lookup, "run", mt(I.class), + samMT, mh, instMT); + if (!correct) { + throw new AssertionError("Unexpected linkage without error:" + + " impl=" + mh + + ", inst=" + instMT + + ", sam=" + samMT); + } + } + catch (LambdaConversionException e) { + if (correct) { + throw new AssertionError("Unexpected linkage error:" + + " e=" + e + + ", impl=" + mh + + ", inst=" + instMT + + ", sam=" + samMT); + } + } + } + + static void tryAltMetafactory(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, + MethodType... bridgeMTs) { + boolean bridge = bridgeMTs.length > 0; + Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4]; + args[0] = samMT; + args[1] = mh; + args[2] = instMT; + args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0; + if (bridge) { + args[4] = bridgeMTs.length; + for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i]; + } + try { + LambdaMetafactory.altMetafactory(lookup, "run", mt(I.class), args); + if (!correct) { + throw new AssertionError("Unexpected linkage without error:" + + " impl=" + mh + + ", inst=" + instMT + + ", sam=" + samMT + + ", bridges=" + Arrays.toString(bridgeMTs)); + } + } + catch (LambdaConversionException e) { + if (correct) { + throw new AssertionError("Unexpected linkage error:" + + " e=" + e + + ", impl=" + mh + + ", inst=" + instMT + + ", sam=" + samMT + + ", bridges=" + Arrays.toString(bridgeMTs)); + } + } + } + + private static class ConversionTable { + private final Map, Set>> pairs = new HashMap<>(); + + public void put(Class from, Class to) { + Set> set = pairs.computeIfAbsent(from, f -> new HashSet<>()); + set.add(to); + } + + public boolean contains(Class from, Class to) { + return pairs.containsKey(from) && pairs.get(from).contains(to); + } + } + + private static ConversionTable conversions = new ConversionTable(); + static { + conversions.put(char.class, int.class); + conversions.put(char.class, long.class); + conversions.put(char.class, float.class); + conversions.put(char.class, double.class); + conversions.put(char.class, Character.class); + conversions.put(char.class, Object.class); + conversions.put(Character.class, char.class); + conversions.put(Character.class, int.class); + conversions.put(Character.class, long.class); + conversions.put(Character.class, float.class); + conversions.put(Character.class, double.class); + + conversions.put(byte.class, short.class); + conversions.put(byte.class, int.class); + conversions.put(byte.class, long.class); + conversions.put(byte.class, float.class); + conversions.put(byte.class, double.class); + conversions.put(byte.class, Byte.class); + conversions.put(byte.class, Object.class); + conversions.put(Byte.class, byte.class); + conversions.put(Byte.class, short.class); + conversions.put(Byte.class, int.class); + conversions.put(Byte.class, long.class); + conversions.put(Byte.class, float.class); + conversions.put(Byte.class, double.class); + + conversions.put(short.class, int.class); + conversions.put(short.class, long.class); + conversions.put(short.class, float.class); + conversions.put(short.class, double.class); + conversions.put(short.class, Short.class); + conversions.put(short.class, Object.class); + conversions.put(Short.class, short.class); + conversions.put(Short.class, int.class); + conversions.put(Short.class, long.class); + conversions.put(Short.class, float.class); + conversions.put(Short.class, double.class); + + conversions.put(int.class, long.class); + conversions.put(int.class, float.class); + conversions.put(int.class, double.class); + conversions.put(int.class, Integer.class); + conversions.put(int.class, Object.class); + conversions.put(Integer.class, int.class); + conversions.put(Integer.class, long.class); + conversions.put(Integer.class, float.class); + conversions.put(Integer.class, double.class); + + conversions.put(long.class, float.class); + conversions.put(long.class, double.class); + conversions.put(long.class, Long.class); + conversions.put(long.class, Object.class); + conversions.put(Long.class, long.class); + conversions.put(Long.class, float.class); + conversions.put(Long.class, double.class); + + conversions.put(float.class, double.class); + conversions.put(float.class, Float.class); + conversions.put(float.class, Object.class); + conversions.put(Float.class, float.class); + conversions.put(Float.class, double.class); + + conversions.put(double.class, Double.class); + conversions.put(double.class, Object.class); + conversions.put(Double.class, double.class); + + conversions.put(boolean.class, Boolean.class); + conversions.put(boolean.class, Object.class); + conversions.put(Boolean.class, boolean.class); + } + +} diff --git a/jdk/test/java/lang/invoke/lambda/MetafactoryMethodNameTest.java b/jdk/test/java/lang/invoke/lambda/MetafactoryMethodNameTest.java new file mode 100644 index 00000000000..64dd4b45d37 --- /dev/null +++ b/jdk/test/java/lang/invoke/lambda/MetafactoryMethodNameTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8173587 + * @summary metafactory should fail if the method name is not legal + */ +import java.lang.invoke.*; +import java.util.*; + +public class MetafactoryMethodNameTest { + + public static void main(String... args) { + goodName("x"); + goodName("xy"); + + goodName("]"); + goodName("x]"); + goodName("]y"); + goodName("x]y"); + + goodName("&"); + goodName("x&"); + goodName("&y"); + goodName("x&y"); + + badName("."); + badName("x."); + badName(".y"); + badName("x.y"); + + badName(";"); + badName("x;"); + badName(";y"); + badName("x;y"); + + badName("["); + badName("x["); + badName("[y"); + badName("x[y"); + + badName("/"); + badName("x/"); + badName("/y"); + badName("x/y"); + + badName("<"); + badName("x<"); + badName(""); + badName("x>"); + badName(">y"); + badName("x>y"); + + badName(""); + badName(""); + badName(""); + } + + static MethodType mt(Class ret, Class... params) { + return MethodType.methodType(ret, params); + } + + static MethodHandle smh(Class c, String name, MethodType desc) { + try { + return MethodHandles.lookup().findStatic(c, name, desc); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + static Object[] arr(Object... args) { + return args; + } + + public static class C { + public static void m() {} + } + + public interface I {} + + private static MethodHandles.Lookup lookup = MethodHandles.lookup(); + private static MethodType toI = mt(I.class); + private static MethodType toVoid = mt(void.class); + private static MethodHandle mh = smh(C.class, "m", toVoid); + private static Class lce = LambdaConversionException.class; + + static void goodName(String name) { + succeedMFLinkage(lookup, name, toI, toVoid, mh, toVoid); + succeedAltMFLinkage(lookup, name, toI, arr(toVoid, mh, toVoid, LambdaMetafactory.FLAG_SERIALIZABLE)); + } + + static void badName(String name) { + failMFLinkage(lookup, name, toI, toVoid, mh, toVoid, lce); + failAltMFLinkage(lookup, name, toI, arr(toVoid, mh, toVoid, LambdaMetafactory.FLAG_SERIALIZABLE), lce); + } + + static CallSite succeedMFLinkage(MethodHandles.Lookup lookup, + String name, + MethodType capType, + MethodType desc, + MethodHandle impl, + MethodType checked) { + try { + return LambdaMetafactory.metafactory(lookup, name, capType, desc, impl, checked); + } catch (Throwable t) { + String msg = String.format("Unexpected exception during linkage for metafactory(%s, %s, %s, %s, %s, %s)", + lookup, name, capType, desc, impl, checked); + throw new AssertionError(msg, t); + } + } + + static void failMFLinkage(MethodHandles.Lookup lookup, + String name, + MethodType capType, + MethodType desc, + MethodHandle impl, + MethodType checked, + Class expectedExceptionType) { + try { + LambdaMetafactory.metafactory(lookup, name, capType, desc, impl, checked); + } catch (Throwable t) { + if (expectedExceptionType.isInstance(t)) { + return; + } else { + String msg = String.format("Unexpected exception: expected %s during linkage for metafactory(%s, %s, %s, %s, %s, %s)", + expectedExceptionType.getName(), + lookup, name, capType, desc, impl, checked); + throw new AssertionError(msg, t); + } + } + String msg = String.format("Unexpected success: expected %s during linkage for metafactory(%s, %s, %s, %s, %s, %s)", + expectedExceptionType.getName(), + lookup, name, capType, desc, impl, checked); + throw new AssertionError(msg); + } + + static CallSite succeedAltMFLinkage(MethodHandles.Lookup lookup, + String name, + MethodType capType, + Object[] args) { + try { + return LambdaMetafactory.altMetafactory(lookup, name, capType, args); + } catch (Throwable t) { + String msg = String.format("Unexpected exception during linkage for metafactory(%s, %s, %s, %s)", + lookup, name, capType, Arrays.asList(args)); + throw new AssertionError(msg, t); + } + } + + static void failAltMFLinkage(MethodHandles.Lookup lookup, + String name, + MethodType capType, + Object[] args, + Class expectedExceptionType) { + try { + LambdaMetafactory.altMetafactory(lookup, name, capType, args); + } catch (Throwable t) { + if (expectedExceptionType.isInstance(t)) { + return; + } else { + String msg = String.format("Unexpected exception: expected %s during linkage for metafactory(%s, %s, %s, %s)", + expectedExceptionType.getName(), + lookup, name, capType, Arrays.asList(args)); + throw new AssertionError(msg, t); + } + } + String msg = String.format("Unexpected success: expected %s during linkage for metafactory(%s, %s, %s, %s)", + expectedExceptionType.getName(), + lookup, name, capType, Arrays.asList(args)); + throw new AssertionError(msg); + } + +} diff --git a/jdk/test/java/lang/invoke/lambda/MetafactorySamReturnTest.java b/jdk/test/java/lang/invoke/lambda/MetafactorySamReturnTest.java deleted file mode 100644 index 4caf2624df9..00000000000 --- a/jdk/test/java/lang/invoke/lambda/MetafactorySamReturnTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 8035776 - * @summary metafactory should fail if impl return does not match sam/bridge returns - */ -import java.lang.invoke.*; -import java.util.Arrays; -import static java.lang.invoke.MethodType.methodType; - -public class MetafactorySamReturnTest { - - static final MethodHandles.Lookup lookup = MethodHandles.lookup(); - - public interface I {} - - public static class C { - public static void m_void(String arg) {} - public static boolean m_boolean(String arg) { return true; } - public static char m_char(String arg) { return 'x'; } - public static byte m_byte(String arg) { return 12; } - public static short m_short(String arg) { return 12; } - public static int m_int(String arg) { return 12; } - public static long m_long(String arg) { return 12; } - public static float m_float(String arg) { return 12; } - public static double m_double(String arg) { return 12; } - public static String m_String(String arg) { return ""; } - public static Integer m_Integer(String arg) { return 23; } - public static Object m_Object(String arg) { return new Object(); } - - public static MethodHandle getMH(Class c) { - try { - return lookup.findStatic(C.class, "m_" + c.getSimpleName(), methodType(c, String.class)); - } - catch (NoSuchMethodException | IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - - public static void main(String... args) { - Class[] t = { void.class, boolean.class, char.class, - byte.class, short.class, int.class, long.class, float.class, double.class, - String.class, Integer.class, Object.class }; - - for (int i = 0; i < t.length; i++) { - MethodHandle mh = C.getMH(t[i]); - for (int j = 0; j < t.length; j++) { - // TEMPORARY EXCEPTIONS - if (t[j] == void.class) continue; - if (t[i].isPrimitive() && t[j] == Object.class) continue; - if (t[i] == char.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; - if (t[i] == byte.class && (t[j] == short.class || t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; - if (t[i] == short.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; - if (t[i] == int.class && (t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; - if (t[i] == long.class && (t[j] == float.class || t[j] == double.class)) continue; - if (t[i] == float.class && t[j] == double.class) continue; - if (t[i] == int.class && t[j] == Integer.class) continue; - if (t[i] == Integer.class && (t[j] == int.class || t[j] == long.class || t[j] == float.class || t[j] == double.class)) continue; - // END TEMPORARY EXCEPTIONS - boolean correct = (t[i].isPrimitive() || t[j].isPrimitive()) - ? t[i] == t[j] - : t[j].isAssignableFrom(t[i]); - MethodType mti = methodType(t[i], String.class); - MethodType mtiCS = methodType(t[i], CharSequence.class); - MethodType mtj = methodType(t[j], String.class); - MethodType mtjObj = methodType(t[j], Object.class); - test(correct, mh, mti, mtj); - testBridge(correct, mh, mti, mti, mtjObj); - testBridge(correct, mh, mti, mti, mtiCS, mtjObj); - } - } - } - - static void test(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT) { - tryMetafactory(correct, mh, new Class[]{}, instMT, samMT); - tryAltMetafactory(correct, mh, new Class[]{}, instMT, samMT); - } - - static void testBridge(boolean correct, MethodHandle mh, MethodType instMT, MethodType samMT, MethodType... bridgeMTs) { - tryAltMetafactory(correct, mh, new Class[]{}, instMT, samMT, bridgeMTs); - } - - static void tryMetafactory(boolean correct, MethodHandle mh, Class[] captured, - MethodType instMT, MethodType samMT) { - try { - LambdaMetafactory.metafactory(lookup, "run", methodType(I.class, captured), - samMT, mh, instMT); - if (!correct) { - throw new AssertionError("Uncaught linkage error:" + - " impl=" + mh + - ", captured=" + Arrays.toString(captured) + - ", inst=" + instMT + - ", sam=" + samMT); - } - } - catch (LambdaConversionException e) { - if (correct) { - throw new AssertionError("Unexpected linkage error:" + - " e=" + e + - ", impl=" + mh + - ", captured=" + Arrays.toString(captured) + - ", inst=" + instMT + - ", sam=" + samMT); - } - } - } - - static void tryAltMetafactory(boolean correct, MethodHandle mh, Class[] captured, - MethodType instMT, MethodType samMT, MethodType... bridgeMTs) { - boolean bridge = bridgeMTs.length > 0; - Object[] args = new Object[bridge ? 5+bridgeMTs.length : 4]; - args[0] = samMT; - args[1] = mh; - args[2] = instMT; - args[3] = bridge ? LambdaMetafactory.FLAG_BRIDGES : 0; - if (bridge) { - args[4] = bridgeMTs.length; - for (int i = 0; i < bridgeMTs.length; i++) args[5+i] = bridgeMTs[i]; - } - try { - LambdaMetafactory.altMetafactory(lookup, "run", methodType(I.class, captured), args); - if (!correct) { - throw new AssertionError("Uncaught linkage error:" + - " impl=" + mh + - ", captured=" + Arrays.toString(captured) + - ", inst=" + instMT + - ", sam=" + samMT + - ", bridges=" + Arrays.toString(bridgeMTs)); - } - } - catch (LambdaConversionException e) { - if (correct) { - throw new AssertionError("Unexpected linkage error:" + - " e=" + e + - ", impl=" + mh + - ", captured=" + Arrays.toString(captured) + - ", inst=" + instMT + - ", sam=" + samMT + - ", bridges=" + Arrays.toString(bridgeMTs)); - } - } - } - -} diff --git a/jdk/test/java/lang/invoke/modules/Driver.java b/jdk/test/java/lang/invoke/modules/Driver.java new file mode 100644 index 00000000000..5c00de3ad47 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/Driver.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 + * @build m1/* m2/* Unnamed + * @run testng/othervm m1/p1.Main + * @summary Basic test case for module access checks and Lookup.in. + */ diff --git a/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java b/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java deleted file mode 100644 index 32adfd9d5e0..00000000000 --- a/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; - -import static jdk.testlibrary.ProcessTools.executeTestJava; - -import org.testng.annotations.BeforeTest; -import org.testng.annotations.Test; -import static org.testng.Assert.*; - -/** - * @test - * @library /lib/testlibrary - * @modules jdk.compiler - * @build CompilerUtils jdk.testlibrary.* - * @run testng ModuleAccessControlTest - * @summary Driver for testing module access checking by MethodHandles.Lookup - */ - -public class ModuleAccessControlTest { - - private static final String TEST_SRC = System.getProperty("test.src"); - - private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); - private static final Path MODS_DIR = Paths.get("mods"); - - // the names of the modules in this test - private static List modules = Arrays.asList("m1", "m2"); - - - /** - * Compiles all modules used by the test - */ - @BeforeTest - public void compileAll() throws Exception { - for (String mn : modules) { - Path msrc = SRC_DIR.resolve(mn); - assertTrue(CompilerUtils - .compile(msrc, MODS_DIR, "--module-source-path", SRC_DIR.toString())); - } - } - - /** - * Launch the test - */ - @Test - public void runTest() throws Exception { - int exitValue = executeTestJava("--module-path", MODS_DIR.toString(), - "-m", "m1/p1.Main") - .outputTo(System.out) - .errorTo(System.out) - .getExitValue(); - - assertTrue(exitValue == 0); - } - -} diff --git a/jdk/test/java/lang/invoke/modules/Unnamed.java b/jdk/test/java/lang/invoke/modules/Unnamed.java new file mode 100644 index 00000000000..9bb0ff042a3 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/Unnamed.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +public class Unnamed { } diff --git a/jdk/test/java/lang/invoke/modules/src/m1/module-info.java b/jdk/test/java/lang/invoke/modules/m1/module-info.java similarity index 98% rename from jdk/test/java/lang/invoke/modules/src/m1/module-info.java rename to jdk/test/java/lang/invoke/modules/m1/module-info.java index 175c7727611..9c09afcf7e1 100644 --- a/jdk/test/java/lang/invoke/modules/src/m1/module-info.java +++ b/jdk/test/java/lang/invoke/modules/m1/module-info.java @@ -22,5 +22,6 @@ */ module m1 { requires m2; + requires testng; exports p1; } diff --git a/jdk/test/java/lang/invoke/modules/m1/p1/Main.java b/jdk/test/java/lang/invoke/modules/m1/p1/Main.java new file mode 100644 index 00000000000..7a10022d78f --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/m1/p1/Main.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * 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 p1; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; + +import static java.lang.invoke.MethodHandles.Lookup.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * Basic test case for module access checks and Lookup.in. + */ + +@Test +public class Main { + + private Class p1_Type1; // m1, exported + private Class p2_Type2; // m1, not exported + private Class q1_Type1; // m2, exported + private Class q2_Type2; // m2, not exported + private Class x500NameClass; // java.base, not exported + private Class unnamedClass; // class in unnamed module + + @BeforeTest + public void setup() throws Exception { + try { + p1_Type1 = Class.forName("p1.Type1"); + p2_Type2 = Class.forName("p2.Type2"); + q1_Type1 = Class.forName("q1.Type1"); + q2_Type2 = Class.forName("q2.Type2"); + x500NameClass = Class.forName("sun.security.x509.X500Name"); + unnamedClass = Class.forName("Unnamed"); + } catch (ClassNotFoundException e) { + throw new AssertionError(e); + } + + // check setup + Module m1 = Layer.boot().findModule("m1").orElse(null); + assertNotNull(m1); + assertTrue(p1_Type1.getModule() == m1); + assertTrue(p2_Type2.getModule() == m1); + assertTrue(m1.isExported("p1")); + assertFalse(m1.isExported("p2")); + + Module m2 = Layer.boot().findModule("m2").orElse(null); + assertNotNull(m2); + assertTrue(q1_Type1.getModule() == m2); + assertTrue(q2_Type2.getModule() == m2); + assertTrue(m2.isExported("q1")); + assertFalse(m2.isExported("q2")); + + Module unnamedModule = unnamedClass.getModule(); + assertFalse(unnamedModule.isNamed()); + + // m1 needs to read unnamed module + Main.class.getModule().addReads(unnamedModule); + } + + /** + * MethodHandles.lookup() + * + * [A0] has module access + * [A1] can access all public types in m1 + * [A2] can access public types in packages exported by modules that m1 reads + * [A3] cannot access public types in non-exported modules of modules that m1 reads + */ + public void testLookup() throws Exception { + Lookup lookup = MethodHandles.lookup(); + assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0] + + // m1 + findConstructor(lookup, p1_Type1, void.class); // [A1] + findConstructor(lookup, p2_Type2, void.class); // [A1] + + // m2 + findConstructor(lookup, q1_Type1, void.class); // [A2] + findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3] + + // java.base + findConstructor(lookup, Object.class, void.class); // [A2] + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3] + + // unnamed + findConstructor(lookup, unnamedClass, void.class); // [A3] + } + + /** + * Hop to lookup class in the same module + * + * [A0] module and public access is not lost + */ + public void testToSameModule() throws Exception { + Lookup lookup = MethodHandles.lookup().in(p2_Type2); + assertTrue(lookup.lookupModes() == (MODULE|PUBLIC)); // [A0] + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructor(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Hop to lookup class in another named module + * + * [A0] has no access + */ + public void testFromNamedToNamedModule() throws Exception { + Lookup lookup = MethodHandles.lookup().in(q1_Type1); + assertTrue(lookup.lookupModes() == 0); // [A0] + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructorExpectingIAE(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + /** + * Hop to lookup class in an unnamed module + * + * [A0] has no access + */ + public void testFromNamedToUnnamedModule() throws Exception { + Lookup lookup = MethodHandles.lookup().in(unnamedClass); + assertTrue(lookup.lookupModes() == 0); // [A0] + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructorExpectingIAE(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + /** + * Hop from unnamed to named module. + * + * [A0] retains PUBLIC access + */ + public void testFromUnnamedToNamedModule() throws Exception { + Lookup lookup = MethodHandles.lookup(); + lookup = MethodHandles.privateLookupIn(unnamedClass, lookup).in(p1_Type1); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * MethodHandles.publicLookup() + * + * [A0] has PUBLIC|UNCONDITIONAL access + */ + public void testPublicLookup() throws Exception { + Lookup lookup = MethodHandles.publicLookup(); + assertTrue(lookup.lookupModes() == (PUBLIC|UNCONDITIONAL)); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Hop from publicLookup to accessible type in java.base + */ + public void testPublicLookupToBaseModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(String.class); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + + /** + * Hop from publicLookup to accessible type in named module. + * + * [A0] has PUBLIC access + */ + public void testPublicLookupToAccessibleTypeInNamedModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(p1_Type1); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Teleport from publicLookup to inaccessible type in named module. + * + * [A0] has no access + */ + public void testPublicLookupToInaccessibleTypeInNamedModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(p2_Type2); + assertTrue(lookup.lookupModes() == 0); // A0 + + // m1 + findConstructorExpectingIAE(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructorExpectingIAE(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructorExpectingIAE(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructorExpectingIAE(lookup, unnamedClass, void.class); + } + + /** + * Teleport from publicLookup to public type in unnamed module + * + * [A0] has PUBLIC access + */ + public void testPublicLookupToUnnamedModule() throws Exception { + Lookup lookup = MethodHandles.publicLookup().in(unnamedClass); + assertTrue(lookup.lookupModes() == PUBLIC); // A0 + + // m1 + findConstructor(lookup, p1_Type1, void.class); + findConstructorExpectingIAE(lookup, p2_Type2, void.class); + + // m2 + findConstructor(lookup, q1_Type1, void.class); + findConstructorExpectingIAE(lookup, q2_Type2, void.class); + + // java.base + findConstructor(lookup, Object.class, void.class); + findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); + + // unnamed + findConstructor(lookup, unnamedClass, void.class); + } + + /** + * Invokes Lookup findConstructor with a method type constructored from the + * given return and parameter types, expecting IllegalAccessException to be + * thrown. + */ + static void findConstructorExpectingIAE(Lookup lookup, + Class clazz, + Class rtype, + Class... ptypes) throws Exception { + try { + findConstructor(lookup, clazz, rtype, ptypes); + assertTrue(false); + } catch (IllegalAccessException expected) { } + } + + /** + * Invokes Lookup findConstructor with a method type constructored from the + * given return and parameter types. + */ + static MethodHandle findConstructor(Lookup lookup, + Class clazz, + Class rtype, + Class... ptypes) throws Exception { + MethodType mt = MethodType.methodType(rtype, ptypes); + return lookup.findConstructor(clazz, mt); + } +} diff --git a/jdk/test/java/lang/invoke/modules/src/m1/p1/Type1.java b/jdk/test/java/lang/invoke/modules/m1/p1/Type1.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m1/p1/Type1.java rename to jdk/test/java/lang/invoke/modules/m1/p1/Type1.java diff --git a/jdk/test/java/lang/invoke/modules/src/m1/p2/Type2.java b/jdk/test/java/lang/invoke/modules/m1/p2/Type2.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m1/p2/Type2.java rename to jdk/test/java/lang/invoke/modules/m1/p2/Type2.java diff --git a/jdk/test/java/lang/invoke/modules/src/m2/module-info.java b/jdk/test/java/lang/invoke/modules/m2/module-info.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m2/module-info.java rename to jdk/test/java/lang/invoke/modules/m2/module-info.java diff --git a/jdk/test/java/lang/invoke/modules/src/m2/q1/Type1.java b/jdk/test/java/lang/invoke/modules/m2/q1/Type1.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m2/q1/Type1.java rename to jdk/test/java/lang/invoke/modules/m2/q1/Type1.java diff --git a/jdk/test/java/lang/invoke/modules/src/m2/q2/Type2.java b/jdk/test/java/lang/invoke/modules/m2/q2/Type2.java similarity index 100% rename from jdk/test/java/lang/invoke/modules/src/m2/q2/Type2.java rename to jdk/test/java/lang/invoke/modules/m2/q2/Type2.java diff --git a/jdk/test/java/lang/invoke/modules/src/m1/p1/Main.java b/jdk/test/java/lang/invoke/modules/src/m1/p1/Main.java deleted file mode 100644 index 3fd1a0eb43d..00000000000 --- a/jdk/test/java/lang/invoke/modules/src/m1/p1/Main.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * 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 p1; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodHandles.Lookup; -import java.lang.invoke.MethodType; - -/** - * Basic test case for module access check, supplements AccessControlTest. - * - * The tests consists of two modules: - * - * module m1 { requires m2; exports p1; } - * module m2 { exports q1; } - * - * Both modules read java.base (as every module reads java.base) - * - * module m1 has public types in packages p1 and p2, p2 is not exported. - * module m2 has public types in packages q1 and q2, q2 is not exported. - */ - -public class Main { - - static final int MODULE = Lookup.MODULE; - - // Use Class.forName to get classes for test because some - // are not accessible at compile-time - - static final Class p1_Type1; // m1, exported - static final Class p2_Type2; // m1, not exported - static final Class q1_Type1; // m2, exported, m1 reads m2 - static final Class q2_Type2; // m2, not exported, m1 reads m2 - static final Class x500NameClass; // java.base, not exported - - static { - try { - p1_Type1 = Class.forName("p1.Type1"); - p2_Type2 = Class.forName("p2.Type2"); - q1_Type1 = Class.forName("q1.Type1"); - q2_Type2 = Class.forName("q2.Type2"); - x500NameClass = Class.forName("sun.security.x509.X500Name"); - } catch (ClassNotFoundException e) { - throw new AssertionError(e); - } - } - - public static void main(String[] args) throws Exception { - Lookup lookup, lookup2; - - /** - * MethodHandles.lookup() - * has module access [A0] - * can access all public types in m1 [A1] - * can access public types in packages exported by modules that m1 reads [A2] - * cannot access public types in non-exported modules of modules that m1 reads [A3] - */ - lookup = MethodHandles.lookup(); - assertTrue((lookup.lookupModes() & MODULE) == MODULE); // [A0] - findConstructor(lookup, p1_Type1, void.class); // [A1] - findConstructor(lookup, p2_Type2, void.class); // [A1] - findConstructor(lookup, q1_Type1, void.class); // [A2] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A3] - findConstructor(lookup, Object.class, void.class); // [A2] - findConstructorExpectingIAE(lookup, x500NameClass, void.class, String.class); // [A3] - - /** - * Teleport from MethodHandles.lookup() to lookup class in the same module - * module access is retained [A0] - * can access all public types in m1 [A1] - * can access public types in packages exported by modules that m1 reads [A2] - * cannot access public types in non-exported modules of modules that m1 reads [A3] - */ - lookup2 = lookup.in(p2_Type2); - assertTrue((lookup2.lookupModes() & MODULE) == MODULE); // [A0] - findConstructor(lookup2, p1_Type1, void.class); // [A1] - findConstructor(lookup2, p2_Type2, void.class); // [A1] - findConstructor(lookup2, q1_Type1, void.class); // [A2] - findConstructorExpectingIAE(lookup2, q2_Type2, void.class); // [A3] - findConstructor(lookup2, Object.class, void.class); // [A2] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A3] - - /** - * Teleport from MethodHandles.lookup() to lookup class in another named module - * has no access [A0] - */ - lookup2 = lookup.in(Object.class); - assertTrue(lookup2.lookupModes() == 0); // [A0] - findConstructorExpectingIAE(lookup2, Object.class, void.class); // [A0] - - /** - * Teleport from MethodHandles.lookup() to lookup class in an unnamed module - * has no access [A0] - */ - Class c = MethodHandles.publicLookup().lookupClass(); - assertTrue(!c.getModule().isNamed()); - lookup2 = lookup.in(c); - assertTrue(lookup2.lookupModes() == 0); // [A0] - findConstructorExpectingIAE(lookup2, Object.class, void.class); - - /** - * MethodHandles.publicLookup() - * has no module access [A0] - * can access public types in exported packages [A1] - * cannot access public types in non-exported packages [A2] - */ - lookup = MethodHandles.publicLookup(); - assertTrue((lookup.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup, p1_Type1, void.class); // [A1] - findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A1] - findConstructor(lookup, q1_Type1, void.class); // [A1] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2] - findConstructor(lookup, Object.class, void.class); // [A1] - findConstructorExpectingIAE(lookup, x500NameClass, void.class); // [A2] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class in java.base - * has no module access [A0] - * can access public types in packages exported by java.base [A1] - * cannot access public types in non-exported packages [A2] - * no access to types in other named modules [A3] - */ - lookup2 = lookup.in(Object.class); - assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup2, String.class, void.class); // [A1] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2] - findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A3] - findConstructorExpectingIAE(lookup2, q1_Type1, void.class); // [A3] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class in m1 - * has no module access [A0] - * can access public types in packages exported by m1, m2 and java.base [A1] - * cannot access public types is non-exported packages [A2] - */ - lookup2 = lookup.in(p1_Type1); - assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup2, p1_Type1, void.class); // [A1] - findConstructor(lookup2, q1_Type1, void.class); // [A1] - findConstructor(lookup2, Object.class, void.class); // [A1] - findConstructorExpectingIAE(lookup, p2_Type2, void.class); // [A2] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class in m2 - * has no module access [A0] - * can access public types in packages exported by m2 and java.base [A1] - * cannot access public types is non-exported packages or modules that m2 does - * not read [A2] - */ - lookup2 = lookup.in(q1_Type1); - assertTrue((lookup2.lookupModes() & MODULE) == 0); // [A0] - findConstructor(lookup2, q1_Type1, void.class); // [A1] - findConstructor(lookup2, Object.class, void.class); // [A1] - findConstructorExpectingIAE(lookup2, p1_Type1, void.class); // [A2] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A2] - findConstructorExpectingIAE(lookup2, x500NameClass, void.class, String.class); // [A2] - - /** - * Teleport from MethodHandles.publicLookup() to lookup class that is not - * in an exported package, should get no access [A0] - */ - lookup2 = lookup.in(p2_Type2); - assertTrue(lookup2.lookupModes() == 0); // [A0] - findConstructorExpectingIAE(lookup, q2_Type2, void.class); // [A0] - } - - /** - * Invokes Lookup findConstructor with a method type constructored from the - * given return and parameter types, expecting IllegalAccessException to be - * thrown. - */ - static MethodHandle findConstructorExpectingIAE(Lookup lookup, - Class clazz, - Class rtype, - Class... ptypes) throws Exception { - try { - findConstructor(lookup, clazz, rtype, ptypes); - throw new RuntimeException("IllegalAccessError expected"); - } catch (IllegalAccessException expected) { - return null; - } - } - - /** - * Invokes Lookup findConstructor with a method type constructored from the - * given return and parameter types. - */ - static MethodHandle findConstructor(Lookup lookup, - Class clazz, - Class rtype, - Class... ptypes) throws Exception { - MethodType mt = MethodType.methodType(rtype, ptypes); - return lookup.findConstructor(clazz, mt); - } - - static void assertTrue(boolean condition) { - if (!condition) - throw new RuntimeException(); - } - -} diff --git a/jdk/test/java/lang/module/AutomaticModulesTest.java b/jdk/test/java/lang/module/AutomaticModulesTest.java index 07d25b9be85..1c020c309f2 100644 --- a/jdk/test/java/lang/module/AutomaticModulesTest.java +++ b/jdk/test/java/lang/module/AutomaticModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,10 +33,10 @@ import java.io.IOException; import java.lang.module.Configuration; import java.lang.module.FindException; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; +import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; import java.lang.reflect.Module; @@ -137,6 +137,7 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), mn + " not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); assertEquals(descriptor.name(), mn); if (vs == null) { assertFalse(descriptor.version().isPresent()); @@ -175,17 +176,14 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); assertTrue(descriptor.packages().size() == 2); assertTrue(descriptor.packages().contains("p")); assertTrue(descriptor.packages().contains("q")); - Set exports = descriptor.exports().stream() - .map(Exports::source) - .collect(Collectors.toSet()); - assertTrue(exports.size() == 2); - assertTrue(exports.contains("p")); - assertTrue(exports.contains("q")); + assertTrue(descriptor.exports().isEmpty()); + assertTrue(descriptor.opens().isEmpty()); } /** @@ -201,15 +199,13 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); assertTrue(descriptor.packages().size() == 1); assertTrue(descriptor.packages().contains("p")); - Set exports = descriptor.exports().stream() - .map(Exports::source) - .collect(Collectors.toSet()); - assertTrue(exports.size() == 1); - assertTrue(exports.contains("p")); + assertTrue(descriptor.exports().isEmpty()); + assertTrue(descriptor.opens().isEmpty()); } /** @@ -229,10 +225,10 @@ public class AutomaticModulesTest { assertTrue(mref.isPresent(), "m not found"); ModuleDescriptor descriptor = mref.get().descriptor(); + assertTrue(descriptor.isAutomatic()); - assertTrue(descriptor.packages().size() == 2); + assertTrue(descriptor.packages().size() == 1); assertTrue(descriptor.packages().contains("p")); - assertTrue(descriptor.packages().contains("p.resources")); } /** @@ -254,9 +250,17 @@ public class AutomaticModulesTest { String provider = "p.S1"; Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); + + // provider class + Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class"); + Files.createDirectories(providerClass.getParent()); + Files.createFile(providerClass); + + // services configuration file Path services = tmpdir.resolve("META-INF").resolve("services"); Files.createDirectories(services); Files.write(services.resolve(service), Set.of(provider)); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); @@ -314,7 +318,7 @@ public class AutomaticModulesTest { // service type provider type { "p.S", "-" }, - { "p.S", ".S1" }, + { "p.S", "p..S1" }, { "p.S", "S1." }, }; } @@ -324,13 +328,41 @@ public class AutomaticModulesTest { * values or names. */ @Test(dataProvider = "badproviders", expectedExceptions = FindException.class) - public void testBadProvideNames(String service, String provider) + public void testBadProviderNames(String service, String provider) throws IOException { Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); + + // provider class + Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class"); + Files.createDirectories(providerClass.getParent()); + Files.createFile(providerClass); + + // services configuration file Path services = tmpdir.resolve("META-INF").resolve("services"); Files.createDirectories(services); Files.write(services.resolve(service), Set.of(provider)); + + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); + + // should throw FindException + ModuleFinder.of(dir).findAll(); + } + + /** + * Test JAR file with META-INF/services configuration file listing a + * provider that is not in the module. + */ + @Test(expectedExceptions = FindException.class) + public void testMissingProviderPackage() throws IOException { + Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp"); + + // services configuration file + Path services = tmpdir.resolve("META-INF").resolve("services"); + Files.createDirectories(services); + Files.write(services.resolve("p.S"), Set.of("q.P")); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir); @@ -352,7 +384,8 @@ public class AutomaticModulesTest { attrs.put(Attributes.Name.MAIN_CLASS, mainClass); Path dir = Files.createTempDirectory(USER_DIR, "mods"); - createDummyJarFile(dir.resolve("m.jar"), man); + String entry = mainClass.replace('.', '/') + ".class"; + createDummyJarFile(dir.resolve("m.jar"), man, entry); ModuleFinder finder = ModuleFinder.of(dir); @@ -366,20 +399,21 @@ public class AutomaticModulesTest { } - // Main-Class files that do not map to a legal Java identifier + // Main-Class files that do not map to a legal qualified type name @DataProvider(name = "badmainclass") public Object[][] createBadMainClass() { return new Object[][]{ + { "Main", null }, + { "p..Main", null }, { "p-.Main", null }, - { ".Main", null } }; } /** - * Test that a JAR file with a Main-Class attribute that is not a valid - * Java identifier + * Test that a JAR file with a Main-Class attribute that is not a qualified + * type name. */ @Test(dataProvider = "badmainclass", expectedExceptions = FindException.class) public void testBadMainClass(String mainClass, String ignore) throws IOException { @@ -388,6 +422,24 @@ public class AutomaticModulesTest { attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); attrs.put(Attributes.Name.MAIN_CLASS, mainClass); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + String entry = mainClass.replace('.', '/') + ".class"; + createDummyJarFile(dir.resolve("m.jar"), man, entry); + + // should throw FindException + ModuleFinder.of(dir).findAll(); + } + + /** + * Test that a JAR file with a Main-Class attribute that is not in the module + */ + @Test(expectedExceptions = FindException.class) + public void testMissingMainClassPackage() throws IOException { + Manifest man = new Manifest(); + Attributes attrs = man.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); + attrs.put(Attributes.Name.MAIN_CLASS, "p.Main"); + Path dir = Files.createTempDirectory(USER_DIR, "mods"); createDummyJarFile(dir.resolve("m.jar"), man); @@ -405,7 +457,7 @@ public class AutomaticModulesTest { */ public void testConfiguration1() throws Exception { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("c") .requires("java.base") @@ -465,13 +517,13 @@ public class AutomaticModulesTest { */ public void testInConfiguration2() throws IOException { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("java.base") .build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("b") + = ModuleDescriptor.newModule("b") .requires("c") .requires("java.base") .build(); @@ -538,13 +590,13 @@ public class AutomaticModulesTest { */ public void testInConfiguration3() throws IOException { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("java.base") .build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("b") + = ModuleDescriptor.newModule("b") .requires(Set.of(Modifier.TRANSITIVE), "c") .requires("java.base") .build(); @@ -608,12 +660,68 @@ public class AutomaticModulesTest { } + /** + * Basic test of a configuration created with automatic modules + * a requires b* and c* + * b* contains p + * c* contains p + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testDuplicateSuppliers1() throws IOException { + ModuleDescriptor descriptor + = ModuleDescriptor.newModule("a") + .requires("b") + .requires("c") + .build(); + + // c and d are automatic modules with the same package + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); + createDummyJarFile(dir.resolve("c.jar"), "p/T.class"); + + // module finder locates 'a' and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + resolve(parent, finder, "a"); + } + + + /** + * Basic test of a configuration created with automatic modules + * a contains p, requires b* + * b* contains p + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testDuplicateSuppliers2() throws IOException { + ModuleDescriptor descriptor + = ModuleDescriptor.newModule("a") + .packages(Set.of("p")) + .requires("b") + .build(); + + // c and d are automatic modules with the same package + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); + + // module finder locates 'a' and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + resolve(parent, finder, "a"); + } + + /** * Basic test of Layer containing automatic modules */ public void testInLayer() throws IOException { ModuleDescriptor descriptor - = ModuleDescriptor.module("a") + = ModuleDescriptor.newModule("a") .requires("b") .requires("c") .build(); @@ -664,7 +772,7 @@ public class AutomaticModulesTest { // test miscellaneous methods assertTrue(m.isAutomatic()); - assertFalse(m.isSynthetic()); + assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)); assertFalse(m.osName().isPresent()); assertFalse(m.osArch().isPresent()); assertFalse(m.osVersion().isPresent()); @@ -672,12 +780,12 @@ public class AutomaticModulesTest { /** - * Invokes parent.resolveRequires to resolve the given root modules. + * Invokes parent.resolve to resolve the given root modules. */ static Configuration resolve(Configuration parent, ModuleFinder finder, String... roots) { - return parent.resolveRequires(finder, ModuleFinder.of(), Set.of(roots)); + return parent.resolve(finder, ModuleFinder.of(), Set.of(roots)); } /** diff --git a/jdk/test/java/lang/module/ConfigurationTest.java b/jdk/test/java/lang/module/ConfigurationTest.java index 7ae867217c6..28f414736b1 100644 --- a/jdk/test/java/lang/module/ConfigurationTest.java +++ b/jdk/test/java/lang/module/ConfigurationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,23 +24,26 @@ /** * @test * @library /lib/testlibrary + * @modules java.base/jdk.internal.misc * @build ConfigurationTest ModuleUtils * @run testng ConfigurationTest * @summary Basic tests for java.lang.module.Configuration */ import java.lang.module.Configuration; +import java.lang.module.FindException; import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleFinder; import java.lang.module.ResolutionException; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; -import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import jdk.internal.misc.SharedSecrets; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -48,30 +51,35 @@ import static org.testng.Assert.*; @Test public class ConfigurationTest { + /** + * Creates a "non-strict" builder for building a module. This allows the + * test the create ModuleDescriptor objects that do not require java.base. + */ + private static ModuleDescriptor.Builder newBuilder(String mn) { + return SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder(mn, false, Set.of()); + } /** * Basic test of resolver * m1 requires m2, m2 requires m3 */ public void testBasic() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 3); @@ -110,24 +118,21 @@ public class ConfigurationTest { */ public void testRequiresTransitive1() { // m1 requires m2, m2 requires transitive m3 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 3); @@ -167,18 +172,16 @@ public class ConfigurationTest { // cf1: m1 and m2, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); @@ -196,14 +199,13 @@ public class ConfigurationTest { // cf2: m3, m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -231,13 +233,11 @@ public class ConfigurationTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); @@ -250,19 +250,17 @@ public class ConfigurationTest { // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -297,13 +295,11 @@ public class ConfigurationTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); @@ -316,14 +312,13 @@ public class ConfigurationTest { // cf2: m2 requires transitive m1 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequires(cf1, finder2, "m2"); + Configuration cf2 = resolve(cf1, finder2, "m2"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -340,14 +335,13 @@ public class ConfigurationTest { // cf3: m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); - Configuration cf3 = resolveRequires(cf2, finder3, "m3"); + Configuration cf3 = resolve(cf2, finder3, "m3"); assertTrue(cf3.modules().size() == 1); assertTrue(cf3.findModule("m1").isPresent()); // in parent @@ -376,18 +370,16 @@ public class ConfigurationTest { // cf1: m1, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); @@ -408,20 +400,18 @@ public class ConfigurationTest { // cf2: m3 requires transitive m2, m4 requires m3 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m3") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4"); + Configuration cf2 = resolve(cf1, finder2, "m3", "m4"); assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m1").isPresent()); // in parent @@ -456,28 +446,24 @@ public class ConfigurationTest { * - Configuration cf3(cf1,cf2): m4 requires m2, m3 */ public void testRequiresTransitive6() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m2") .requires("m3") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); @@ -485,7 +471,7 @@ public class ConfigurationTest { assertTrue(cf1.parents().get(0) == Configuration.empty()); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); - Configuration cf2 = resolveRequires(finder2, "m3"); + Configuration cf2 = resolve(finder2, "m3"); assertTrue(cf2.modules().size() == 2); assertTrue(cf2.findModule("m3").isPresent()); assertTrue(cf2.findModule("m1").isPresent()); @@ -493,7 +479,7 @@ public class ConfigurationTest { assertTrue(cf2.parents().get(0) == Configuration.empty()); ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4); - Configuration cf3 = Configuration.resolveRequires(finder3, + Configuration cf3 = Configuration.resolve(finder3, List.of(cf1, cf2), ModuleFinder.of(), Set.of("m4")); @@ -522,14 +508,13 @@ public class ConfigurationTest { * resolve m1 */ public void testRequiresStatic1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); @@ -545,18 +530,16 @@ public class ConfigurationTest { * resolve m1 */ public void testRequiresStatic2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); @@ -572,18 +555,16 @@ public class ConfigurationTest { * resolve m1, m2 */ public void testRequiresStatic3() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1", "m2"); + Configuration cf = resolve(finder, "m1", "m2"); assertTrue(cf.modules().size() == 2); @@ -604,25 +585,22 @@ public class ConfigurationTest { * m3 */ public void testRequiresStatic4() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .requires("m3") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.STATIC), "m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder - = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 3); @@ -648,31 +626,28 @@ public class ConfigurationTest { * - Configuration cf2: m3 requires m1, requires static m2 */ public void testRequiresStatic5() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m1", "m2"); + Configuration cf1 = resolve(finder1, "m1", "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m3").isPresent()); @@ -694,26 +669,24 @@ public class ConfigurationTest { * - Configuration cf2: m3 requires m1, requires static m2 */ public void testRequiresStatic6() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .requires(Set.of(Requires.Modifier.STATIC), "m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m3").isPresent()); @@ -735,21 +708,19 @@ public class ConfigurationTest { public void testRequiresStatic7() { ModuleDescriptor descriptor1 = null; // not observable - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE, Requires.Modifier.STATIC), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m3"); + Configuration cf = resolve(finder, "m3"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m2").isPresent()); @@ -770,8 +741,7 @@ public class ConfigurationTest { public void testRequiresStatic8() { ModuleDescriptor descriptor1 = null; // not observable - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE, Requires.Modifier.STATIC), "m1") @@ -779,21 +749,20 @@ public class ConfigurationTest { ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m2").isPresent()); ResolvedModule m2 = cf1.findModule("m2").get(); assertTrue(m2.reads().isEmpty()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m3").isPresent()); @@ -810,22 +779,19 @@ public class ConfigurationTest { */ public void testServiceBinding1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequiresAndUses(finder, "m1"); + Configuration cf = resolveAndBind(finder, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -853,31 +819,26 @@ public class ConfigurationTest { */ public void testServiceBinding2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .uses("p.S2") - .contains("q") - .provides("p.S1", "q.Service1Impl") + .provides("p.S1", List.of("q.Service1Impl")) .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") - .contains("q") - .provides("p.S2", "q.Service2Impl") + .provides("p.S2", List.of("q.Service2Impl")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequiresAndUses(finder, "m1"); + Configuration cf = resolveAndBind(finder, "m1"); assertTrue(cf.modules().size() == 3); assertTrue(cf.findModule("m1").isPresent()); @@ -912,29 +873,26 @@ public class ConfigurationTest { */ public void testServiceBindingWithConfigurations1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots + Configuration cf2 = resolveAndBind(cf1, finder2); // no roots assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -961,47 +919,39 @@ public class ConfigurationTest { */ public void testServiceBindingWithConfigurations2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") - .contains("p1") - .provides("p.S", "p1.ServiceImpl") + .provides("p.S", List.of("p1.ServiceImpl")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("p2") - .provides("p.S", "p2.ServiceImpl") + .provides("p.S", List.of("p2.ServiceImpl")) .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequiresAndUses(finder1, "m1"); + Configuration cf1 = resolveAndBind(finder1, "m1"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); assertTrue(cf1.findModule("m2").isPresent()); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") - .contains("p3") - .provides("p.S", "p3.ServiceImpl") + .provides("p.S", List.of("p3.ServiceImpl")) .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m1") - .contains("p4") - .provides("p.S", "p4.ServiceImpl") + .provides("p.S", List.of("p4.ServiceImpl")) .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots + Configuration cf2 = resolveAndBind(cf1, finder2); // no roots assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1037,22 +987,19 @@ public class ConfigurationTest { */ public void testServiceBindingWithConfigurations3() { - ModuleDescriptor service - = ModuleDescriptor.module("s") + ModuleDescriptor service = newBuilder("s") .exports("p") .build(); - ModuleDescriptor provider_v1 - = ModuleDescriptor.module("p") + ModuleDescriptor provider_v1 = newBuilder("p") .version("1.0") .requires("s") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder1 = ModuleUtils.finderOf(service, provider_v1); - Configuration cf1 = resolveRequires(finder1, "p"); + Configuration cf1 = resolve(finder1, "p"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("s").isPresent()); @@ -1063,18 +1010,15 @@ public class ConfigurationTest { assertEquals(p.reference().descriptor(), provider_v1); - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("s") .uses("p.S") .build(); - ModuleDescriptor provider_v2 - = ModuleDescriptor.module("p") + ModuleDescriptor provider_v2 = newBuilder("p") .version("2.0") .requires("s") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, provider_v2); @@ -1082,7 +1026,7 @@ public class ConfigurationTest { // finder2 is the before ModuleFinder and so p@2.0 should be located - Configuration cf2 = resolveRequiresAndUses(cf1, finder2, "m1"); + Configuration cf2 = resolveAndBind(cf1, finder2, "m1"); assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1097,7 +1041,7 @@ public class ConfigurationTest { // finder2 is the after ModuleFinder and so p@2.0 should not be located // as module p is in parent configuration. - cf2 = resolveRequiresAndUses(cf1, ModuleFinder.of(), finder2, "m1"); + cf2 = resolveAndBind(cf1, ModuleFinder.of(), finder2, "m1"); assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1117,25 +1061,22 @@ public class ConfigurationTest { */ public void testWithTwoFinders1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2_v1 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v1 = newBuilder("m2") .version("1.0") .build(); - ModuleDescriptor descriptor2_v2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v2 = newBuilder("m2") .version("2.0") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2_v1); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2_v2); - Configuration cf = resolveRequires(finder1, finder2, "m1"); + Configuration cf = resolve(finder1, finder2, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -1157,30 +1098,25 @@ public class ConfigurationTest { */ public void testWithTwoFinders2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2_v1 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v1 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); - ModuleDescriptor descriptor2_v2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2_v2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2_v1); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2_v2); - Configuration cf = resolveRequiresAndUses(finder1, finder2, "m1"); + Configuration cf = resolveAndBind(finder1, finder2, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -1200,18 +1136,17 @@ public class ConfigurationTest { */ public void testResolvedInParent1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder, "m1"); + Configuration cf1 = resolve(finder, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - Configuration cf2 = resolveRequires(cf1, finder, "m1"); + Configuration cf2 = resolve(cf1, finder, "m1"); assertTrue(cf2.modules().size() == 1); } @@ -1223,26 +1158,23 @@ public class ConfigurationTest { */ public void testResolvedInParent2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequires(cf1, ModuleFinder.of(), finder2, "m2"); + Configuration cf2 = resolve(cf1, ModuleFinder.of(), finder2, "m2"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m2").isPresent()); @@ -1268,29 +1200,28 @@ public class ConfigurationTest { public void testResolvedInMultipleParents1() { // Configuration cf1: m1 - ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertEquals(cf1.parents(), List.of(Configuration.empty())); assertTrue(cf1.findModule("m1").isPresent()); ResolvedModule m1 = cf1.findModule("m1").get(); assertTrue(m1.configuration() == cf1); // Configuration cf2: m2 - ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build(); - Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2"); + ModuleDescriptor descriptor2 = newBuilder("m2").build(); + Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2"); assertEquals(cf2.parents(), List.of(Configuration.empty())); assertTrue(cf2.findModule("m2").isPresent()); ResolvedModule m2 = cf2.findModule("m2").get(); assertTrue(m2.configuration() == cf2); // Configuration cf3(cf1,cf2): m3 requires m1 and m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .requires("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor3); - Configuration cf3 = Configuration.resolveRequires( + Configuration cf3 = Configuration.resolve( finder, List.of(cf1, cf2), // parents ModuleFinder.of(), @@ -1319,19 +1250,18 @@ public class ConfigurationTest { */ public void testResolvedInMultipleParents2() { // Configuration cf1: m1 - ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertEquals(cf1.parents(), List.of(Configuration.empty())); assertTrue(cf1.findModule("m1").isPresent()); ResolvedModule m1 = cf1.findModule("m1").get(); assertTrue(m1.configuration() == cf1); // Configuration cf2(cf1): m2 requires m1 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .build(); - Configuration cf2 = Configuration.resolveRequires( + Configuration cf2 = Configuration.resolve( ModuleUtils.finderOf(descriptor2), List.of(cf1), // parents ModuleFinder.of(), @@ -1342,11 +1272,10 @@ public class ConfigurationTest { assertTrue(m2.configuration() == cf2); // Configuration cf3(cf1): m3 requires m1 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m1") .build(); - Configuration cf3 = Configuration.resolveRequires( + Configuration cf3 = Configuration.resolve( ModuleUtils.finderOf(descriptor3), List.of(cf1), // parents ModuleFinder.of(), @@ -1357,13 +1286,12 @@ public class ConfigurationTest { assertTrue(m3.configuration() == cf3); // Configuration cf4(cf2,cf3): m4 requires m1,m2,m3 - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m1") .requires("m2") .requires("m3") .build(); - Configuration cf4 = Configuration.resolveRequires( + Configuration cf4 = Configuration.resolve( ModuleUtils.finderOf(descriptor4), List.of(cf2, cf3), // parents ModuleFinder.of(), @@ -1395,35 +1323,34 @@ public class ConfigurationTest { ModuleDescriptor descriptor1, descriptor2, descriptor3; // Configuration cf1: m1@1 - descriptor1 = ModuleDescriptor.module("m1").version("1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + descriptor1 = newBuilder("m1").version("1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertEquals(cf1.parents(), List.of(Configuration.empty())); // Configuration cf2: m1@2, m2@2 - descriptor1 = ModuleDescriptor.module("m1").version("2").build(); - descriptor2 = ModuleDescriptor.module("m2").version("2").build(); - Configuration cf2 = resolveRequires( + descriptor1 = newBuilder("m1").version("2").build(); + descriptor2 = newBuilder("m2").version("2").build(); + Configuration cf2 = resolve( ModuleUtils.finderOf(descriptor1, descriptor2), "m1", "m2"); assertEquals(cf2.parents(), List.of(Configuration.empty())); // Configuration cf3: m1@3, m2@3, m3@3 - descriptor1 = ModuleDescriptor.module("m1").version("3").build(); - descriptor2 = ModuleDescriptor.module("m2").version("3").build(); - descriptor3 = ModuleDescriptor.module("m3").version("3").build(); - Configuration cf3 = resolveRequires( + descriptor1 = newBuilder("m1").version("3").build(); + descriptor2 = newBuilder("m2").version("3").build(); + descriptor3 = newBuilder("m3").version("3").build(); + Configuration cf3 = resolve( ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3), "m1", "m2", "m3"); assertEquals(cf3.parents(), List.of(Configuration.empty())); // Configuration cf4(cf1,cf2,cf3): m4 requires m1,m2,m3 - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m1") .requires("m2") .requires("m3") .build(); - Configuration cf4 = Configuration.resolveRequires( + Configuration cf4 = Configuration.resolve( ModuleUtils.finderOf(descriptor4), List.of(cf1, cf2, cf3), // parents ModuleFinder.of(), @@ -1470,17 +1397,15 @@ public class ConfigurationTest { * configuration. */ public void testOverriding1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder, "m1"); + Configuration cf1 = resolve(finder, "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - Configuration cf2 = resolveRequires(cf1, finder, "m1"); + Configuration cf2 = resolve(cf1, finder, "m1"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m1").isPresent()); } @@ -1490,24 +1415,24 @@ public class ConfigurationTest { * configuration. */ public void testOverriding2() { - ModuleDescriptor descriptor1 = ModuleDescriptor.module("m1").build(); - Configuration cf1 = resolveRequires(ModuleUtils.finderOf(descriptor1), "m1"); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); + Configuration cf1 = resolve(ModuleUtils.finderOf(descriptor1), "m1"); assertTrue(cf1.modules().size() == 1); assertTrue(cf1.findModule("m1").isPresent()); - ModuleDescriptor descriptor2 = ModuleDescriptor.module("m2").build(); - Configuration cf2 = resolveRequires(ModuleUtils.finderOf(descriptor2), "m2"); + ModuleDescriptor descriptor2 = newBuilder("m2").build(); + Configuration cf2 = resolve(ModuleUtils.finderOf(descriptor2), "m2"); assertTrue(cf2.modules().size() == 1); assertTrue(cf2.findModule("m2").isPresent()); - ModuleDescriptor descriptor3 = ModuleDescriptor.module("m3").build(); - Configuration cf3 = resolveRequires(ModuleUtils.finderOf(descriptor3), "m3"); + ModuleDescriptor descriptor3 = newBuilder("m3").build(); + Configuration cf3 = resolve(ModuleUtils.finderOf(descriptor3), "m3"); assertTrue(cf3.modules().size() == 1); assertTrue(cf3.findModule("m3").isPresent()); // override m2, m1 and m3 should be found in parent configurations ModuleFinder finder = ModuleUtils.finderOf(descriptor2); - Configuration cf4 = Configuration.resolveRequires( + Configuration cf4 = Configuration.resolve( finder, List.of(cf1, cf2, cf3), ModuleFinder.of(), @@ -1530,18 +1455,16 @@ public class ConfigurationTest { */ public void testOverriding3() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); assertTrue(cf1.findModule("m1").isPresent()); @@ -1549,14 +1472,13 @@ public class ConfigurationTest { // cf2: m3 requires m2, m1 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m1", "m3"); + Configuration cf2 = resolve(cf1, finder2, "m1", "m3"); assertTrue(cf2.parents().size() == 1); assertTrue(cf2.parents().get(0) == cf1); @@ -1585,64 +1507,58 @@ public class ConfigurationTest { /** * Root module not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testRootNotFound() { - resolveRequires(ModuleFinder.of(), "m1"); + resolve(ModuleFinder.of(), "m1"); } /** * Direct dependency not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testDirectDependencyNotFound() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").requires("m2").build(); + ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } /** * Transitive dependency not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testTransitiveDependencyNotFound() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").requires("m2").build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").requires("m3").build(); + ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build(); + ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } /** * Service provider dependency not found */ - @Test(expectedExceptions = { ResolutionException.class }) + @Test(expectedExceptions = { FindException.class }) public void testServiceProviderDependencyNotFound() { // service provider dependency (on m3) not found - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .requires("m3") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // should throw ResolutionException because m3 is not found - Configuration cf = resolveRequiresAndUses(finder, "m1"); + Configuration cf = resolveAndBind(finder, "m1"); } @@ -1651,15 +1567,12 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testSimpleCycle() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").requires("m2").build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").requires("m3").build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3").requires("m1").build(); + ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build(); + ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build(); + ModuleDescriptor descriptor3 = newBuilder("m3").requires("m1").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } /** @@ -1668,20 +1581,16 @@ public class ConfigurationTest { @Test(expectedExceptions = { ResolutionException.class }) public void testCycleInProvider() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .requires("m3") - .contains("q") - .provides("p.S", "q.T") + .provides("p.S", List.of("q.T")) .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); @@ -1689,7 +1598,7 @@ public class ConfigurationTest { = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // should throw ResolutionException because of the m2 <--> m3 cycle - resolveRequiresAndUses(finder, "m1"); + resolveAndBind(finder, "m1"); } @@ -1699,19 +1608,16 @@ public class ConfigurationTest { @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedByTwoOthers() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .requires("m3") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .exports("p", Set.of("m1")) .build(); @@ -1719,7 +1625,7 @@ public class ConfigurationTest { = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // m2 and m3 export package p to module m1 - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } @@ -1730,21 +1636,19 @@ public class ConfigurationTest { @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedBySelfAndOther() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") - .contains("p") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m1 contains package p, module m2 exports package p to m1 - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } @@ -1753,20 +1657,18 @@ public class ConfigurationTest { * a module that also contains a package p. */ public void testContainsPackageInSelfAndOther() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") - .contains("p") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") - .contains("p") + ModuleDescriptor descriptor2 = newBuilder("m2") + .packages(Set.of("p")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -1787,8 +1689,7 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testExportSamePackageAsBootLayer() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor = newBuilder("m1") .requires("java.base") .exports("java.lang") .build(); @@ -1798,7 +1699,7 @@ public class ConfigurationTest { Configuration bootConfiguration = Layer.boot().configuration(); // m1 contains package java.lang, java.base exports package java.lang to m1 - resolveRequires(bootConfiguration, finder, "m1"); + resolve(bootConfiguration, finder, "m1"); } @@ -1806,15 +1707,14 @@ public class ConfigurationTest { * Test "uses p.S" where p is contained in the same module. */ public void testContainsService1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p")) .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); assertTrue(cf.findModule("m1").isPresent()); @@ -1826,13 +1726,11 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testContainsService2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .uses("p.S") .build(); @@ -1840,7 +1738,7 @@ public class ConfigurationTest { ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p - resolveRequires(finder, "m2"); + resolve(finder, "m2"); } @@ -1848,16 +1746,14 @@ public class ConfigurationTest { * Test "provides p.S" where p is contained in the same module. */ public void testContainsService3() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") - .contains("q") - .provides("p.S", "q.S1") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p", "q")) + .provides("p.S", List.of("q.S1")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 1); assertTrue(cf.findModule("m1").isPresent()); @@ -1869,22 +1765,19 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testContainsService4() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor descriptor1 = newBuilder("m1") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") - .contains("q") - .provides("p.S", "q.S1") + .provides("p.S", List.of("q.S1")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p - resolveRequires(finder, "m2"); + resolve(finder, "m2"); } @@ -1893,15 +1786,14 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p - resolveRequires(finder, "m1"); + resolve(finder, "m1"); } @@ -1910,40 +1802,14 @@ public class ConfigurationTest { */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("q") - .provides("p.S", "q.T") + ModuleDescriptor descriptor1 = newBuilder("m1") + .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p - resolveRequires(finder, "m1"); - } - - - /** - * Test "provides p.S with q.T" where q.T is not local - */ - @Test(expectedExceptions = { ResolutionException.class }) - public void testProviderPackageNotLocal() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .exports("p") - .exports("q") - .build(); - - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") - .requires("m1") - .provides("p.S", "q.T") - .build(); - - ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - - // q.T not in module m2 - resolveRequires(finder, "m2"); + resolve(finder, "m1"); } @@ -2007,34 +1873,17 @@ public class ConfigurationTest { @Test(dataProvider = "platformmatch") public void testPlatformMatch(String s1, String s2) { - ModuleDescriptor.Builder builder - = ModuleDescriptor.module("m1").requires("m2"); - - String[] s = s1.split("-"); - if (!s[0].equals("*")) - builder.osName(s[0]); - if (!s[1].equals("*")) - builder.osArch(s[1]); - if (!s[2].equals("*")) - builder.osVersion(s[2]); - + Builder builder = newBuilder("m1").requires("m2"); + addPlatformConstraints(builder, s1); ModuleDescriptor descriptor1 = builder.build(); - builder = ModuleDescriptor.module("m2"); - - s = s2.split("-"); - if (!s[0].equals("*")) - builder.osName(s[0]); - if (!s[1].equals("*")) - builder.osArch(s[1]); - if (!s[2].equals("*")) - builder.osVersion(s[2]); - + builder = newBuilder("m2"); + addPlatformConstraints(builder, s2); ModuleDescriptor descriptor2 = builder.build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 2); assertTrue(cf.findModule("m1").isPresent()); @@ -2046,7 +1895,7 @@ public class ConfigurationTest { * platforms. */ @Test(dataProvider = "platformmismatch", - expectedExceptions = ResolutionException.class ) + expectedExceptions = FindException.class ) public void testPlatformMisMatch(String s1, String s2) { testPlatformMatch(s1, s2); } @@ -2057,16 +1906,67 @@ public class ConfigurationTest { @Test(expectedExceptions = { IllegalArgumentException.class }) public void testResolveRequiresWithNoParents() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequires(empty, List.of(), empty, Set.of()); + Configuration.resolve(empty, List.of(), empty, Set.of()); } @Test(expectedExceptions = { IllegalArgumentException.class }) public void testResolveRequiresAndUsesWithNoParents() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequiresAndUses(empty, List.of(), empty, Set.of()); + Configuration.resolveAndBind(empty, List.of(), empty, Set.of()); } + // parents with modules for specific platforms + + @Test(dataProvider = "platformmatch") + public void testResolveRequiresWithCompatibleParents(String s1, String s2) { + Builder builder = newBuilder("m1"); + addPlatformConstraints(builder, s1); + ModuleDescriptor descriptor1 = builder.build(); + + builder = newBuilder("m2"); + addPlatformConstraints(builder, s2); + ModuleDescriptor descriptor2 = builder.build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + Configuration cf2 = resolve(finder2, "m2"); + + Configuration cf3 = Configuration.resolve(ModuleFinder.of(), + List.of(cf1, cf2), + ModuleFinder.of(), + Set.of()); + assertTrue(cf3.parents().size() == 2); + } + + @Test(dataProvider = "platformmismatch", + expectedExceptions = IllegalArgumentException.class ) + public void testResolveRequiresWithConflictingParents(String s1, String s2) { + Builder builder = newBuilder("m1"); + addPlatformConstraints(builder, s1); + ModuleDescriptor descriptor1 = builder.build(); + + builder = newBuilder("m2"); + addPlatformConstraints(builder, s2); + ModuleDescriptor descriptor2 = builder.build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + Configuration cf1 = resolve(finder1, "m1"); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + Configuration cf2 = resolve(finder2, "m2"); + + // should throw IAE + Configuration.resolve(ModuleFinder.of(), + List.of(cf1, cf2), + ModuleFinder.of(), + Set.of()); + } + + + // null handling // finder1, finder2, roots @@ -2074,72 +1974,72 @@ public class ConfigurationTest { @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull1() { - resolveRequires((ModuleFinder)null, ModuleFinder.of()); + resolve((ModuleFinder)null, ModuleFinder.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull2() { - resolveRequires(ModuleFinder.of(), (ModuleFinder)null); + resolve(ModuleFinder.of(), (ModuleFinder)null); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull3() { Configuration empty = Configuration.empty(); - Configuration.resolveRequires(null, List.of(empty), ModuleFinder.of(), Set.of()); + Configuration.resolve(null, List.of(empty), ModuleFinder.of(), Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull4() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequires(empty, null, empty, Set.of()); + Configuration.resolve(empty, null, empty, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull5() { Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequires(ModuleFinder.of(), List.of(cf), null, Set.of()); + Configuration.resolve(ModuleFinder.of(), List.of(cf), null, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresWithNull6() { ModuleFinder empty = ModuleFinder.of(); Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequires(empty, List.of(cf), empty, null); + Configuration.resolve(empty, List.of(cf), empty, null); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull1() { - resolveRequiresAndUses((ModuleFinder) null, ModuleFinder.of()); + resolveAndBind((ModuleFinder) null, ModuleFinder.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull2() { - resolveRequiresAndUses(ModuleFinder.of(), (ModuleFinder) null); + resolveAndBind(ModuleFinder.of(), (ModuleFinder) null); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull3() { Configuration empty = Configuration.empty(); - Configuration.resolveRequiresAndUses(null, List.of(empty), ModuleFinder.of(), Set.of()); + Configuration.resolveAndBind(null, List.of(empty), ModuleFinder.of(), Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull4() { ModuleFinder empty = ModuleFinder.of(); - Configuration.resolveRequiresAndUses(empty, null, empty, Set.of()); + Configuration.resolveAndBind(empty, null, empty, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull5() { Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequiresAndUses(ModuleFinder.of(), List.of(cf), null, Set.of()); + Configuration.resolveAndBind(ModuleFinder.of(), List.of(cf), null, Set.of()); } @Test(expectedExceptions = { NullPointerException.class }) public void testResolveRequiresAndUsesWithNull6() { ModuleFinder empty = ModuleFinder.of(); Configuration cf = Layer.boot().configuration(); - Configuration.resolveRequiresAndUses(empty, List.of(cf), empty, null); + Configuration.resolveAndBind(empty, List.of(cf), empty, null); } @Test(expectedExceptions = { NullPointerException.class }) @@ -2165,58 +2065,58 @@ public class ConfigurationTest { /** - * Invokes parent.resolveRequires(...) + * Invokes parent.resolve(...) */ - private Configuration resolveRequires(Configuration parent, - ModuleFinder before, - ModuleFinder after, - String... roots) { - return parent.resolveRequires(before, after, Set.of(roots)); + private Configuration resolve(Configuration parent, + ModuleFinder before, + ModuleFinder after, + String... roots) { + return parent.resolve(before, after, Set.of(roots)); } - private Configuration resolveRequires(Configuration parent, - ModuleFinder before, - String... roots) { - return resolveRequires(parent, before, ModuleFinder.of(), roots); + private Configuration resolve(Configuration parent, + ModuleFinder before, + String... roots) { + return resolve(parent, before, ModuleFinder.of(), roots); } - private Configuration resolveRequires(ModuleFinder before, - ModuleFinder after, - String... roots) { - return resolveRequires(Configuration.empty(), before, after, roots); + private Configuration resolve(ModuleFinder before, + ModuleFinder after, + String... roots) { + return resolve(Configuration.empty(), before, after, roots); } - private Configuration resolveRequires(ModuleFinder before, - String... roots) { - return resolveRequires(Configuration.empty(), before, roots); + private Configuration resolve(ModuleFinder before, + String... roots) { + return resolve(Configuration.empty(), before, roots); } /** - * Invokes parent.resolveRequiresAndUses(...) + * Invokes parent.resolveAndBind(...) */ - private Configuration resolveRequiresAndUses(Configuration parent, - ModuleFinder before, - ModuleFinder after, - String... roots) { - return parent.resolveRequiresAndUses(before, after, Set.of(roots)); + private Configuration resolveAndBind(Configuration parent, + ModuleFinder before, + ModuleFinder after, + String... roots) { + return parent.resolveAndBind(before, after, Set.of(roots)); } - private Configuration resolveRequiresAndUses(Configuration parent, - ModuleFinder before, - String... roots) { - return resolveRequiresAndUses(parent, before, ModuleFinder.of(), roots); + private Configuration resolveAndBind(Configuration parent, + ModuleFinder before, + String... roots) { + return resolveAndBind(parent, before, ModuleFinder.of(), roots); } - private Configuration resolveRequiresAndUses(ModuleFinder before, - ModuleFinder after, - String... roots) { - return resolveRequiresAndUses(Configuration.empty(), before, after, roots); + private Configuration resolveAndBind(ModuleFinder before, + ModuleFinder after, + String... roots) { + return resolveAndBind(Configuration.empty(), before, after, roots); } - private Configuration resolveRequiresAndUses(ModuleFinder before, - String... roots) { - return resolveRequiresAndUses(Configuration.empty(), before, roots); + private Configuration resolveAndBind(ModuleFinder before, + String... roots) { + return resolveAndBind(Configuration.empty(), before, roots); } @@ -2234,5 +2134,17 @@ public class ConfigurationTest { .anyMatch(mn2::equals); } - + /** + * Decodes the platform string and calls the builder osName/osArch/osVersion + * methods to set the platform constraints. + */ + static void addPlatformConstraints(Builder builder, String platformString) { + String[] s = platformString.split("-"); + if (!s[0].equals("*")) + builder.osName(s[0]); + if (!s[1].equals("*")) + builder.osArch(s[1]); + if (!s[2].equals("*")) + builder.osVersion(s[2]); + } } diff --git a/jdk/test/java/lang/module/ModuleDescriptorTest.java b/jdk/test/java/lang/module/ModuleDescriptorTest.java index 276ecf71048..b16b9e66e92 100644 --- a/jdk/test/java/lang/module/ModuleDescriptorTest.java +++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /** * @test * @modules java.base/jdk.internal.module + * java.base/jdk.internal.misc * @run testng ModuleDescriptorTest * @summary Basic test for java.lang.module.ModuleDescriptor and its builder */ @@ -42,14 +43,19 @@ import java.lang.module.ModuleDescriptor.Requires.Modifier; import java.lang.module.ModuleDescriptor.Version; import java.lang.reflect.Module; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; +import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; +import jdk.internal.misc.SharedSecrets; import jdk.internal.module.ModuleInfoWriter; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -84,21 +90,27 @@ public class ModuleDescriptorTest { // requires private Requires requires(Set mods, String mn) { - return ModuleDescriptor.module("m") - .requires(mods, mn) - .build() - .requires() - .iterator() - .next(); + return requires(mods, mn, null); } private Requires requires(Set mods, String mn, Version v) { - return ModuleDescriptor.module("m") - .requires(mods, mn, v) - .build() - .requires() - .iterator() - .next(); + Builder builder = ModuleDescriptor.newModule("m"); + if (v == null) { + builder.requires(mods, mn); + } else { + builder.requires(mods, mn, v); + } + Set requires = builder.build().requires(); + assertTrue(requires.size() == 2); + Iterator iterator = requires.iterator(); + Requires r = iterator.next(); + if (r.name().equals("java.base")) { + r = iterator.next(); + } else { + Requires other = iterator.next(); + assertEquals(other.name(), "java.base"); + } + return r; } private Requires requires(String mn) { @@ -107,7 +119,7 @@ public class ModuleDescriptorTest { public void testRequiresWithRequires() { Requires r1 = requires("foo"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m").requires(r1).build(); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").requires(r1).build(); Requires r2 = descriptor.requires().iterator().next(); assertEquals(r1, r2); } @@ -162,28 +174,28 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class) public void testRequiresWithDuplicatesRequires() { Requires r = requires("foo"); - ModuleDescriptor.module("m").requires(r).requires(r); + ModuleDescriptor.newModule("m").requires(r).requires(r); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithRequires() { Requires r = requires("foo"); - ModuleDescriptor.module("foo").requires(r); + ModuleDescriptor.newModule("foo").requires(r); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithNoModifier() { - ModuleDescriptor.module("m").requires("m"); + ModuleDescriptor.newModule("m").requires("m"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithOneModifier() { - ModuleDescriptor.module("m").requires(Set.of(TRANSITIVE), "m"); + ModuleDescriptor.newModule("m").requires(Set.of(TRANSITIVE), "m"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testRequiresSelfWithAllModifiers() { - ModuleDescriptor.module("m").requires(EnumSet.allOf(Modifier.class), "m"); + ModuleDescriptor.newModule("m").requires(EnumSet.allOf(Modifier.class), "m"); } @Test(dataProvider = "invalidjavaidentifiers", @@ -194,17 +206,17 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = NullPointerException.class) public void testRequiresWithNullRequires() { - ModuleDescriptor.module("m").requires((Requires) null); + ModuleDescriptor.newModule("m").requires((Requires) null); } @Test(expectedExceptions = NullPointerException.class) public void testRequiresWithNullModifiers() { - ModuleDescriptor.module("m").requires(null, "foo"); + ModuleDescriptor.newModule("m").requires(null, "foo"); } @Test(expectedExceptions = NullPointerException.class) public void testRequiresWithNullVersion() { - ModuleDescriptor.module("m").requires(Set.of(), "foo", null); + ModuleDescriptor.newModule("m").requires(Set.of(), "foo", null); } public void testRequiresCompare() { @@ -284,7 +296,7 @@ public class ModuleDescriptorTest { // exports private Exports exports(Set mods, String pn) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .exports(mods, pn) .build() .exports() @@ -297,7 +309,7 @@ public class ModuleDescriptorTest { } private Exports exports(Set mods, String pn, String target) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .exports(mods, pn, Set.of(target)) .build() .exports() @@ -312,7 +324,7 @@ public class ModuleDescriptorTest { public void testExportsExports() { Exports e1 = exports("p"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m").exports(e1).build(); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").exports(e1).build(); Exports e2 = descriptor.exports().iterator().next(); assertEquals(e1, e2); } @@ -341,7 +353,7 @@ public class ModuleDescriptorTest { targets.add("bar"); targets.add("gus"); Exports e - = ModuleDescriptor.module("foo") + = ModuleDescriptor.newModule("foo") .exports("p", targets) .build() .exports() @@ -380,69 +392,80 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class) public void testExportsWithDuplicate1() { Exports e = exports("p"); - ModuleDescriptor.module("foo").exports(e).exports(e); + ModuleDescriptor.newModule("foo").exports(e).exports(e); } @Test(expectedExceptions = IllegalStateException.class) public void testExportsWithDuplicate2() { - ModuleDescriptor.module("foo").exports("p").exports("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testExportsOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").exports("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testExportsToTargetOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").exports("p", Set.of("bar")); + ModuleDescriptor.newModule("foo").exports("p").exports("p"); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testExportsWithEmptySet() { - ModuleDescriptor.module("foo").exports("p", Collections.emptySet()); + ModuleDescriptor.newModule("foo").exports("p", Collections.emptySet()); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testExportsWithBadName(String pn, String ignore) { - ModuleDescriptor.module("foo").exports(pn); + ModuleDescriptor.newModule("foo").exports(pn); } @Test(expectedExceptions = NullPointerException.class ) public void testExportsWithNullExports() { - ModuleDescriptor.module("foo").exports((Exports) null); + ModuleDescriptor.newModule("foo").exports((Exports) null); } @Test(expectedExceptions = NullPointerException.class ) public void testExportsWithNullTargets() { - ModuleDescriptor.module("foo").exports("p", (Set) null); + ModuleDescriptor.newModule("foo").exports("p", (Set) null); } - public void testExportsEqualsAndHashCode() { - Exports e1, e2; - - e1 = exports("p"); - e2 = exports("p"); + public void testExportsCompare() { + Exports e1 = exports("p"); + Exports e2 = exports("p"); assertEquals(e1, e2); assertTrue(e1.hashCode() == e2.hashCode()); + assertTrue(e1.compareTo(e2) == 0); + assertTrue(e2.compareTo(e1) == 0); + } - e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); - e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + public void testExportsCompareWithSameModifiers() { + Exports e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + Exports e2 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); assertEquals(e1, e2); assertTrue(e1.hashCode() == e2.hashCode()); + assertTrue(e1.compareTo(e2) == 0); + assertTrue(e2.compareTo(e1) == 0); + } - e1 = exports("p"); - e2 = exports("q"); + public void testExportsCompareWithDifferentModifiers() { + Exports e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); + Exports e2 = exports("p"); assertNotEquals(e1, e2); + assertTrue(e1.compareTo(e2) == 1); + assertTrue(e2.compareTo(e1) == -1); + } - e1 = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); - e2 = exports(Set.of(), "p"); + public void testExportsCompareWithSameTargets() { + Exports e1 = exports("p", "x"); + Exports e2 = exports("p", "x"); + assertEquals(e1, e2); + assertTrue(e1.hashCode() == e2.hashCode()); + assertTrue(e1.compareTo(e2) == 0); + assertTrue(e2.compareTo(e1) == 0); + } + + public void testExportsCompareWithDifferentTargets() { + Exports e1 = exports("p", "y"); + Exports e2 = exports("p", "x"); assertNotEquals(e1, e2); + assertTrue(e1.compareTo(e2) == 1); + assertTrue(e2.compareTo(e1) == -1); } public void testExportsToString() { - String s = ModuleDescriptor.module("foo") + String s = ModuleDescriptor.newModule("foo") .exports("p1", Set.of("bar")) .build() .exports() @@ -457,7 +480,7 @@ public class ModuleDescriptorTest { // opens private Opens opens(Set mods, String pn) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .opens(mods, pn) .build() .opens() @@ -470,7 +493,7 @@ public class ModuleDescriptorTest { } private Opens opens(Set mods, String pn, String target) { - return ModuleDescriptor.module("foo") + return ModuleDescriptor.newModule("foo") .opens(mods, pn, Set.of(target)) .build() .opens() @@ -484,7 +507,7 @@ public class ModuleDescriptorTest { public void testOpensOpens() { Opens o1 = opens("p"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m").opens(o1).build(); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m").opens(o1).build(); Opens o2 = descriptor.opens().iterator().next(); assertEquals(o1, o2); } @@ -513,7 +536,7 @@ public class ModuleDescriptorTest { Set targets = new HashSet<>(); targets.add("bar"); targets.add("gus"); - Opens o = ModuleDescriptor.module("foo") + Opens o = ModuleDescriptor.newModule("foo") .opens("p", targets) .build() .opens() @@ -528,98 +551,83 @@ public class ModuleDescriptorTest { assertTrue(o.targets().contains("gus")); } - /* - - public void testOpensToAllWithModifier() { - Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p"); - assertEquals(e, e); - assertTrue(e.modifiers().size() == 1); - assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); - assertEquals(e.source(), "p"); - assertFalse(e.isQualified()); - assertTrue(e.targets().isEmpty()); - } - - public void testOpensToTargetWithModifier() { - Exports e = exports(Set.of(Exports.Modifier.SYNTHETIC), "p", Set.of("bar")); - assertEquals(e, e); - assertTrue(e.modifiers().size() == 1); - assertTrue(e.modifiers().contains(Exports.Modifier.SYNTHETIC)); - assertEquals(e.source(), "p"); - assertTrue(e.isQualified()); - assertTrue(e.targets().size() == 1); - assertTrue(e.targets().contains("bar")); - } - - - */ - @Test(expectedExceptions = IllegalStateException.class) public void testOpensWithDuplicate1() { Opens o = opens("p"); - ModuleDescriptor.module("foo").opens(o).opens(o); + ModuleDescriptor.newModule("foo").opens(o).opens(o); } @Test(expectedExceptions = IllegalStateException.class) public void testOpensWithDuplicate2() { - ModuleDescriptor.module("foo").opens("p").opens("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testOpensOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").opens("p"); - } - - @Test(expectedExceptions = IllegalStateException.class) - public void testOpensToTargetOnContainedPackage() { - ModuleDescriptor.module("foo").contains("p").opens("p", Set.of("bar")); + ModuleDescriptor.newModule("foo").opens("p").opens("p"); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testOpensWithEmptySet() { - ModuleDescriptor.module("foo").opens("p", Collections.emptySet()); + ModuleDescriptor.newModule("foo").opens("p", Collections.emptySet()); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testOpensWithBadName(String pn, String ignore) { - ModuleDescriptor.module("foo").opens(pn); + ModuleDescriptor.newModule("foo").opens(pn); } @Test(expectedExceptions = NullPointerException.class ) public void testOpensWithNullExports() { - ModuleDescriptor.module("foo").opens((Opens) null); + ModuleDescriptor.newModule("foo").opens((Opens) null); } @Test(expectedExceptions = NullPointerException.class ) public void testOpensWithNullTargets() { - ModuleDescriptor.module("foo").opens("p", (Set) null); + ModuleDescriptor.newModule("foo").opens("p", (Set) null); } - public void testOpensEqualsAndHashCode() { - Opens o1, o2; - - o1 = opens("p"); - o2 = opens("p"); - assertEquals(o1, o2); - assertTrue(o1.hashCode() == o1.hashCode()); - - o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); - o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + public void testOpensCompare() { + Opens o1 = opens("p"); + Opens o2 = opens("p"); assertEquals(o1, o2); assertTrue(o1.hashCode() == o2.hashCode()); + assertTrue(o1.compareTo(o2) == 0); + assertTrue(o2.compareTo(o1) == 0); + } - o1 = opens("p"); - o2 = opens("q"); - assertNotEquals(o1, o2); + public void testOpensCompareWithSameModifiers() { + Opens o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + Opens o2 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + assertEquals(o1, o2); + assertTrue(o1.hashCode() == o2.hashCode()); + assertTrue(o1.compareTo(o2) == 0); + assertTrue(o2.compareTo(o1) == 0); + } - o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); - o2 = opens(Set.of(), "p"); + public void testOpensCompareWithDifferentModifiers() { + Opens o1 = opens(Set.of(Opens.Modifier.SYNTHETIC), "p"); + Opens o2 = opens("p"); assertNotEquals(o1, o2); + assertTrue(o1.compareTo(o2) == 1); + assertTrue(o2.compareTo(o1) == -1); + } + + public void testOpensCompareWithSameTargets() { + Opens o1 = opens("p", "x"); + Opens o2 = opens("p", "x"); + assertEquals(o1, o2); + assertTrue(o1.hashCode() == o2.hashCode()); + assertTrue(o1.compareTo(o2) == 0); + assertTrue(o2.compareTo(o1) == 0); + } + + public void testOpensCompareWithDifferentTargets() { + Opens o1 = opens("p", "y"); + Opens o2 = opens("p", "x"); + assertNotEquals(o1, o2); + assertTrue(o1.compareTo(o2) == 1); + assertTrue(o2.compareTo(o1) == -1); } public void testOpensToString() { - String s = ModuleDescriptor.module("foo") + String s = ModuleDescriptor.newModule("foo") .opens("p1", Set.of("bar")) .build() .opens() @@ -635,7 +643,7 @@ public class ModuleDescriptorTest { public void testUses() { Set uses - = ModuleDescriptor.module("foo") + = ModuleDescriptor.newModule("foo") .uses("p.S") .uses("q.S") .build() @@ -647,30 +655,44 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class) public void testUsesWithDuplicate() { - ModuleDescriptor.module("foo").uses("p.S").uses("p.S"); + ModuleDescriptor.newModule("foo").uses("p.S").uses("p.S"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testUsesWithSimpleIdentifier() { + ModuleDescriptor.newModule("foo").uses("S"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testUsesWithBadName(String service, String ignore) { - ModuleDescriptor.module("foo").uses(service); + ModuleDescriptor.newModule("foo").uses(service); } // provides private Provides provides(String st, String pc) { - return ModuleDescriptor.module("foo") - .provides(st, pc) + return ModuleDescriptor.newModule("foo") + .provides(st, List.of(pc)) .build() .provides() .iterator() .next(); } + private Provides provides(String st, List pns) { + return ModuleDescriptor.newModule("foo") + .provides(st, pns) + .build() + .provides() + .iterator() + .next(); + } + public void testProvidesWithProvides() { Provides p1 = provides("p.S", "q.S1"); - ModuleDescriptor descriptor = ModuleDescriptor.module("m") + ModuleDescriptor descriptor = ModuleDescriptor.newModule("m") .provides(p1) .build(); Provides p2 = descriptor.provides().iterator().next(); @@ -679,7 +701,7 @@ public class ModuleDescriptorTest { public void testProvides() { - Set set = ModuleDescriptor.module("foo") + Set set = ModuleDescriptor.newModule("foo") .provides("p.S", List.of("q.P1", "q.P2")) .build() .provides(); @@ -696,59 +718,86 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = IllegalStateException.class ) public void testProvidesWithDuplicateProvides() { Provides p = provides("p.S", "q.S2"); - ModuleDescriptor.module("m").provides("p.S", "q.S1").provides(p); + ModuleDescriptor.newModule("m").provides("p.S", List.of("q.S1")).provides(p); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithEmptySet() { - ModuleDescriptor.module("foo").provides("p.Service", Collections.emptyList()); + ModuleDescriptor.newModule("foo").provides("p.Service", Collections.emptyList()); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testProvidesWithSimpleIdentifier1() { + ModuleDescriptor.newModule("foo").provides("S", List.of("q.P")); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testProvidesWithSimpleIdentifier2() { + ModuleDescriptor.newModule("foo").provides("p.S", List.of("P")); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithBadService(String service, String ignore) { - ModuleDescriptor.module("foo").provides(service, "p.Provider"); + ModuleDescriptor.newModule("foo").provides(service, List.of("p.Provider")); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testProvidesWithBadProvider(String provider, String ignore) { - ModuleDescriptor.module("foo").provides("p.Service", provider); + List names = new ArrayList<>(); // allows nulls + names.add(provider); + ModuleDescriptor.newModule("foo").provides("p.Service", names); } @Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProvides() { - ModuleDescriptor.module("foo").provides((Provides) null); + ModuleDescriptor.newModule("foo").provides((Provides) null); } @Test(expectedExceptions = NullPointerException.class ) public void testProvidesWithNullProviders() { - ModuleDescriptor.module("foo").provides("p.S", (List) null); + ModuleDescriptor.newModule("foo").provides("p.S", (List) null); } - public void testProvidesEqualsAndHashCode() { - Provides p1, p2; - - p1 = provides("p.S", "q.S1"); - p2 = provides("p.S", "q.S1"); + public void testProvidesCompare() { + Provides p1 = provides("p.S", "q.S1"); + Provides p2 = provides("p.S", "q.S1"); assertEquals(p1, p2); assertTrue(p1.hashCode() == p2.hashCode()); - - p1 = provides("p.S", "q.S1"); - p2 = provides("p.S", "q.S2"); - assertNotEquals(p1, p2); - - p1 = provides("p.S", "q.S1"); - p2 = provides("p.S2", "q.S1"); - assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 0); + assertTrue(p2.compareTo(p1) == 0); } - // contains + public void testProvidesCompareWithDifferentService() { + Provides p1 = provides("p.S2", "q.S1"); + Provides p2 = provides("p.S1", "q.S1"); + assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 1); + assertTrue(p2.compareTo(p1) == -1); + } - public void testContains() { - Set packages = ModuleDescriptor.module("foo") - .contains("p") - .contains("q") + public void testProvidesCompareWithDifferentProviders1() { + Provides p1 = provides("p.S", "q.S2"); + Provides p2 = provides("p.S", "q.S1"); + assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 1); + assertTrue(p2.compareTo(p1) == -1); + } + + public void testProvidesCompareWithDifferentProviders2() { + Provides p1 = provides("p.S", List.of("q.S1", "q.S2")); + Provides p2 = provides("p.S", "q.S1"); + assertNotEquals(p1, p2); + assertTrue(p1.compareTo(p2) == 1); + assertTrue(p2.compareTo(p1) == -1); + } + + // packages + + public void testPackages1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p", "q")) .build() .packages(); assertTrue(packages.size() == 2); @@ -756,56 +805,147 @@ public class ModuleDescriptorTest { assertTrue(packages.contains("q")); } - public void testContainsWithEmptySet() { - Set packages = ModuleDescriptor.module("foo") - .contains(Collections.emptySet()) + public void testPackages2() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .packages(Set.of("q")) + .build() + .packages(); + assertTrue(packages.size() == 2); + assertTrue(packages.contains("p")); + assertTrue(packages.contains("q")); + } + + + public void testPackagesWithEmptySet() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Collections.emptySet()) .build() .packages(); assertTrue(packages.size() == 0); } - @Test(expectedExceptions = IllegalStateException.class) - public void testContainsWithDuplicate() { - ModuleDescriptor.module("foo").contains("p").contains("p"); + public void testPackagesDuplicate() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); } - @Test(expectedExceptions = IllegalStateException.class) - public void testContainsWithExportedPackage() { - ModuleDescriptor.module("foo").exports("p").contains("p"); + public void testPackagesAndExportsPackage1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .exports("p") + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndExportsPackage2() { + Set packages = ModuleDescriptor.newModule("foo") + .exports("p") + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndOpensPackage1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .opens("p") + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndOpensPackage2() { + Set packages = ModuleDescriptor.newModule("foo") + .opens("p") + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndProvides1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .provides("q.S", List.of("p.T")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndProvides2() { + Set packages = ModuleDescriptor.newModule("foo") + .provides("q.S", List.of("p.T")) + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndMainClass1() { + Set packages = ModuleDescriptor.newModule("foo") + .packages(Set.of("p")) + .mainClass("p.Main") + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndMainClass2() { + Set packages = ModuleDescriptor.newModule("foo") + .mainClass("p.Main") + .packages(Set.of("p")) + .build() + .packages(); + assertTrue(packages.size() == 1); + assertTrue(packages.contains("p")); + } + + public void testPackagesAndAll() { + Set packages = ModuleDescriptor.newModule("foo") + .exports("p1") + .opens("p2") + .packages(Set.of("p3")) + .provides("q.S", List.of("p4.T")) + .mainClass("p5.Main") + .build() + .packages(); + assertTrue(Objects.equals(packages, Set.of("p1", "p2", "p3", "p4", "p5"))); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) - public void testContainsWithBadName(String pn, String ignore) { - ModuleDescriptor.module("foo").contains(pn); + public void testPackagesWithBadName(String pn, String ignore) { + Set pkgs = new HashSet<>(); // allows nulls + pkgs.add(pn); + ModuleDescriptor.newModule("foo").packages(pkgs); } - - // packages - - public void testPackages() { - Set packages = ModuleDescriptor.module("foo") - .exports("p") - .contains("q") - .build() - .packages(); - assertTrue(packages.size() == 2); - assertTrue(packages.contains("p")); - assertTrue(packages.contains("q")); - } - - // name public void testModuleName() { - String mn = ModuleDescriptor.module("foo").build().name(); + String mn = ModuleDescriptor.newModule("foo").build().name(); assertEquals(mn, "foo"); } @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testBadModuleName(String mn, String ignore) { - ModuleDescriptor.module(mn); + ModuleDescriptor.newModule(mn); } @@ -813,7 +953,7 @@ public class ModuleDescriptorTest { public void testVersion1() { Version v1 = Version.parse("1.0"); - Version v2 = ModuleDescriptor.module("foo") + Version v2 = ModuleDescriptor.newModule("foo") .version(v1) .build() .version() @@ -823,7 +963,7 @@ public class ModuleDescriptorTest { public void testVersion2() { String vs = "1.0"; - Version v1 = ModuleDescriptor.module("foo") + Version v1 = ModuleDescriptor.newModule("foo") .version(vs) .build() .version() @@ -834,86 +974,178 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = NullPointerException.class ) public void testNullVersion1() { - ModuleDescriptor.module("foo").version((Version) null); + ModuleDescriptor.newModule("foo").version((Version) null); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testNullVersion2() { - ModuleDescriptor.module("foo").version((String) null); + ModuleDescriptor.newModule("foo").version((String) null); } @Test(expectedExceptions = IllegalArgumentException.class ) public void testEmptyVersion() { - ModuleDescriptor.module("foo").version(""); + ModuleDescriptor.newModule("foo").version(""); } // toNameAndVersion public void testToNameAndVersion() { - ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor md1 = ModuleDescriptor.newModule("foo").build(); assertEquals(md1.toNameAndVersion(), "foo"); - ModuleDescriptor md2 = ModuleDescriptor.module("foo").version("1.0").build(); + ModuleDescriptor md2 = ModuleDescriptor.newModule("foo").version("1.0").build(); assertEquals(md2.toNameAndVersion(), "foo@1.0"); } // open modules - public void testOpenModules() { - ModuleDescriptor descriptor = ModuleDescriptor.openModule("m") - .requires("java.base") - .contains("p") + public void testOpenModule() { + ModuleDescriptor descriptor = ModuleDescriptor.newOpenModule("foo") + .requires("bar") + .exports("p") + .provides("p.Service", List.of("q.ServiceImpl")) .build(); + + // modifiers + assertTrue(descriptor.modifiers().contains(ModuleDescriptor.Modifier.OPEN)); assertTrue(descriptor.isOpen()); - assertTrue(descriptor.packages().size() == 1); - assertTrue(descriptor.packages().contains("p")); - assertTrue(descriptor.exports().isEmpty()); + + // requires + assertTrue(descriptor.requires().size() == 2); + Set names = descriptor.requires() + .stream() + .map(Requires::name) + .collect(Collectors.toSet()); + assertEquals(names, Set.of("bar", "java.base")); + + // packages + assertEquals(descriptor.packages(), Set.of("p", "q")); + + // exports + assertTrue(descriptor.exports().size() == 1); + names = descriptor.exports() + .stream() + .map(Exports::source) + .collect(Collectors.toSet()); + assertEquals(names, Set.of("p")); + + // opens + assertTrue(descriptor.opens().isEmpty()); } @Test(expectedExceptions = IllegalStateException.class) - public void testOpensOnWeakModule1() { - ModuleDescriptor.openModule("foo").opens("p"); + public void testOpensOnOpenModule1() { + ModuleDescriptor.newOpenModule("foo").opens("p"); } @Test(expectedExceptions = IllegalStateException.class) - public void testOpensOnWeakModule2() { - ModuleDescriptor.openModule("foo").opens("p", Set.of("bar")); + public void testOpensOnOpenModule2() { + ModuleDescriptor.newOpenModule("foo").opens("p", Set.of("bar")); } public void testIsOpen() { - assertFalse(ModuleDescriptor.module("m").build().isOpen()); - assertFalse(ModuleDescriptor.automaticModule("m").build().isOpen()); - assertTrue(ModuleDescriptor.openModule("m").build().isOpen()); + assertFalse(ModuleDescriptor.newModule("m").build().isOpen()); + assertFalse(ModuleDescriptor.newAutomaticModule("m").build().isOpen()); + assertTrue(ModuleDescriptor.newOpenModule("m").build().isOpen()); } // automatic modules + public void testAutomaticModule() { + ModuleDescriptor descriptor = ModuleDescriptor.newAutomaticModule("foo") + .packages(Set.of("p")) + .provides("p.Service", List.of("q.ServiceImpl")) + .build(); + + // modifiers + assertTrue(descriptor.modifiers().contains(ModuleDescriptor.Modifier.AUTOMATIC)); + assertTrue(descriptor.isAutomatic()); + + // requires + assertTrue(descriptor.requires().size() == 1); + Set names = descriptor.requires() + .stream() + .map(Requires::name) + .collect(Collectors.toSet()); + assertEquals(names, Set.of("java.base")); + + // packages + assertEquals(descriptor.packages(), Set.of("p", "q")); + assertTrue(descriptor.exports().isEmpty()); + assertTrue(descriptor.opens().isEmpty()); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testRequiresOnAutomaticModule() { + ModuleDescriptor.newAutomaticModule("foo").requires("java.base"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsOnAutomaticModule1() { + ModuleDescriptor.newAutomaticModule("foo").exports("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsOnAutomaticModule2() { + ModuleDescriptor.newAutomaticModule("foo").exports("p", Set.of("bar")); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensOnAutomaticModule1() { + ModuleDescriptor.newAutomaticModule("foo").opens("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testOpensOnAutomaticModule2() { + ModuleDescriptor.newAutomaticModule("foo").opens("p", Set.of("bar")); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testUsesOnAutomaticModule() { + ModuleDescriptor.newAutomaticModule("foo").uses("p.Service"); + } + public void testIsAutomatic() { - ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("foo").build(); assertFalse(descriptor1.isAutomatic()); - ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build(); + ModuleDescriptor descriptor2 = ModuleDescriptor.newOpenModule("foo").build(); assertFalse(descriptor2.isAutomatic()); - ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build(); + ModuleDescriptor descriptor3 = ModuleDescriptor.newAutomaticModule("foo").build(); assertTrue(descriptor3.isAutomatic()); } - // isSynthetic - public void testIsSynthetic() { - assertFalse(Object.class.getModule().getDescriptor().isSynthetic()); - ModuleDescriptor descriptor1 = ModuleDescriptor.module("foo").build(); - assertFalse(descriptor1.isSynthetic()); + // newModule with modifiers - ModuleDescriptor descriptor2 = ModuleDescriptor.openModule("foo").build(); - assertFalse(descriptor2.isSynthetic()); + public void testNewModuleToBuildAutomaticModule() { + Set ms = Set.of(ModuleDescriptor.Modifier.AUTOMATIC); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo", ms).build(); + assertTrue(descriptor.modifiers().equals(ms)); + assertTrue(descriptor.isAutomatic()); + } - ModuleDescriptor descriptor3 = ModuleDescriptor.automaticModule("foo").build(); - assertFalse(descriptor3.isSynthetic()); + public void testNewModuleToBuildOpenModule() { + Set ms = Set.of(ModuleDescriptor.Modifier.OPEN); + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo", ms).build(); + assertTrue(descriptor.modifiers().equals(ms)); + assertTrue(descriptor.isOpen()); + + ms = Set.of(ModuleDescriptor.Modifier.OPEN, ModuleDescriptor.Modifier.SYNTHETIC); + descriptor = ModuleDescriptor.newModule("foo", ms).build(); + assertTrue(descriptor.modifiers().equals(ms)); + assertTrue(descriptor.isOpen()); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNewModuleToBuildAutomaticAndOpenModule() { + Set ms = Set.of(ModuleDescriptor.Modifier.AUTOMATIC, + ModuleDescriptor.Modifier.OPEN); + ModuleDescriptor.newModule("foo", ms); } @@ -921,14 +1153,19 @@ public class ModuleDescriptorTest { public void testMainClass() { String mainClass - = ModuleDescriptor.module("foo").mainClass("p.Main").build().mainClass().get(); + = ModuleDescriptor.newModule("foo").mainClass("p.Main").build().mainClass().get(); assertEquals(mainClass, "p.Main"); } + @Test(expectedExceptions = IllegalArgumentException.class) + public void testMainClassWithSimpleIdentifier() { + ModuleDescriptor.newModule("foo").mainClass("Main"); + } + @Test(dataProvider = "invalidjavaidentifiers", expectedExceptions = IllegalArgumentException.class ) public void testMainClassWithBadName(String mainClass, String ignore) { - Builder builder = ModuleDescriptor.module("foo"); + Builder builder = ModuleDescriptor.newModule("foo"); builder.mainClass(mainClass); } @@ -936,54 +1173,54 @@ public class ModuleDescriptorTest { // osName public void testOsName() { - String osName = ModuleDescriptor.module("foo").osName("Linux").build().osName().get(); + String osName = ModuleDescriptor.newModule("foo").osName("Linux").build().osName().get(); assertEquals(osName, "Linux"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsName() { - ModuleDescriptor.module("foo").osName(null); + ModuleDescriptor.newModule("foo").osName(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsName() { - ModuleDescriptor.module("foo").osName(""); + ModuleDescriptor.newModule("foo").osName(""); } // osArch public void testOsArch() { - String osArch = ModuleDescriptor.module("foo").osName("arm").build().osName().get(); + String osArch = ModuleDescriptor.newModule("foo").osName("arm").build().osName().get(); assertEquals(osArch, "arm"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsArch() { - ModuleDescriptor.module("foo").osArch(null); + ModuleDescriptor.newModule("foo").osArch(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsArch() { - ModuleDescriptor.module("foo").osArch(""); + ModuleDescriptor.newModule("foo").osArch(""); } // osVersion public void testOsVersion() { - String osVersion = ModuleDescriptor.module("foo").osName("11.2").build().osName().get(); + String osVersion = ModuleDescriptor.newModule("foo").osName("11.2").build().osName().get(); assertEquals(osVersion, "11.2"); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullOsVersion() { - ModuleDescriptor.module("foo").osVersion(null); + ModuleDescriptor.newModule("foo").osVersion(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testEmptyOsVersion() { - ModuleDescriptor.module("foo").osVersion(""); + ModuleDescriptor.newModule("foo").osVersion(""); } // reads @@ -1023,7 +1260,7 @@ public class ModuleDescriptorTest { * Test ModuleDescriptor with a packager finder */ public void testReadsWithPackageFinder() throws Exception { - ModuleDescriptor descriptor = ModuleDescriptor.module("foo") + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") .requires("java.base") .build(); @@ -1044,7 +1281,7 @@ public class ModuleDescriptorTest { */ @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadsWithBadPackageFinder() throws Exception { - ModuleDescriptor descriptor = ModuleDescriptor.module("foo") + ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo") .requires("java.base") .exports("p") .build(); @@ -1077,7 +1314,7 @@ public class ModuleDescriptorTest { @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadOfJavaBaseWithRequires() { ModuleDescriptor descriptor - = ModuleDescriptor.module("java.base") + = ModuleDescriptor.newModule("java.base") .requires("other") .build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); @@ -1087,7 +1324,8 @@ public class ModuleDescriptorTest { // The requires table must have an entry for java.base @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadWithEmptyRequires() { - ModuleDescriptor descriptor = ModuleDescriptor.module("m1").build(); + ModuleDescriptor descriptor = SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder("m1", false, Set.of()).build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); ModuleDescriptor.read(bb); } @@ -1095,10 +1333,8 @@ public class ModuleDescriptorTest { // The requires table must have an entry for java.base @Test(expectedExceptions = InvalidModuleDescriptorException.class) public void testReadWithNoRequiresBase() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") - .requires("m2") - .build(); + ModuleDescriptor descriptor = SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder("m1", false, Set.of()).requires("m2").build(); ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor); ModuleDescriptor.read(bb); } @@ -1138,22 +1374,50 @@ public class ModuleDescriptorTest { // equals/hashCode/compareTo/toString public void testEqualsAndHashCode() { - ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); - ModuleDescriptor md2 = ModuleDescriptor.module("foo").build(); + ModuleDescriptor md1 = ModuleDescriptor.newModule("m").build(); + ModuleDescriptor md2 = ModuleDescriptor.newModule("m").build(); assertEquals(md1, md1); assertEquals(md1.hashCode(), md2.hashCode()); + assertTrue(md1.compareTo(md2) == 0); + assertTrue(md2.compareTo(md1) == 0); } - public void testCompare() { - ModuleDescriptor md1 = ModuleDescriptor.module("foo").build(); - ModuleDescriptor md2 = ModuleDescriptor.module("bar").build(); - int n = "foo".compareTo("bar"); - assertTrue(md1.compareTo(md2) == n); - assertTrue(md2.compareTo(md1) == -n); + @DataProvider(name = "sortedModuleDescriptors") + public Object[][] sortedModuleDescriptors() { + return new Object[][]{ + + { ModuleDescriptor.newModule("m2").build(), + ModuleDescriptor.newModule("m1").build() + }, + + { ModuleDescriptor.newModule("m").version("2").build(), + ModuleDescriptor.newModule("m").version("1").build() + }, + + { ModuleDescriptor.newModule("m").version("1").build(), + ModuleDescriptor.newModule("m").build() + }, + + { ModuleDescriptor.newOpenModule("m").build(), + ModuleDescriptor.newModule("m").build() + }, + + }; + } + + @Test(dataProvider = "sortedModuleDescriptors") + public void testCompare(ModuleDescriptor md1, ModuleDescriptor md2) { + assertNotEquals(md1, md2); + assertTrue(md1.compareTo(md2) == 1); + assertTrue(md2.compareTo(md1) == -1); } public void testToString() { - String s = ModuleDescriptor.module("m1").requires("m2").exports("p1").build().toString(); + String s = ModuleDescriptor.newModule("m1") + .requires("m2") + .exports("p1") + .build() + .toString(); assertTrue(s.contains("m1")); assertTrue(s.contains("m2")); assertTrue(s.contains("p1")); diff --git a/jdk/test/java/lang/module/ModuleFinderTest.java b/jdk/test/java/lang/module/ModuleFinderTest.java index 278b4b98714..29d8f234c8b 100644 --- a/jdk/test/java/lang/module/ModuleFinderTest.java +++ b/jdk/test/java/lang/module/ModuleFinderTest.java @@ -471,36 +471,10 @@ public class ModuleFinderTest { * Test ModuleFinder.of with a file path to a directory containing a file * that will not be recognized as a module. */ - public void testOfWithUnrecognizedEntryInDirectory() throws Exception { + public void testOfWithUnrecognizedEntryInDirectory1() throws Exception { Path dir = Files.createTempDirectory(USER_DIR, "mods"); Files.createTempFile(dir, "m", ".junk"); - ModuleFinder finder = ModuleFinder.of(dir); - try { - finder.find("java.rhubarb"); - assertTrue(false); - } catch (FindException e) { - // expected - } - - finder = ModuleFinder.of(dir); - try { - finder.findAll(); - assertTrue(false); - } catch (FindException e) { - // expected - } - } - - - /** - * Test ModuleFinder.of with a file path to a directory containing a file - * starting with ".", the file should be ignored. - */ - public void testOfWithHiddenEntryInDirectory() throws Exception { - Path dir = Files.createTempDirectory(USER_DIR, "mods"); - Files.createTempFile(dir, ".marker", ""); - ModuleFinder finder = ModuleFinder.of(dir); assertFalse(finder.find("java.rhubarb").isPresent()); @@ -509,6 +483,24 @@ public class ModuleFinderTest { } + /** + * Test ModuleFinder.of with a file path to a directory containing a file + * that will not be recognized as a module. + */ + public void testOfWithUnrecognizedEntryInDirectory2() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createModularJar(dir.resolve("m1.jar"), "m1"); + Files.createTempFile(dir, "m2", ".junk"); + + ModuleFinder finder = ModuleFinder.of(dir); + assertTrue(finder.find("m1").isPresent()); + assertFalse(finder.find("m2").isPresent()); + + finder = ModuleFinder.of(dir); + assertTrue(finder.findAll().size() == 1); + } + + /** * Test ModuleFinder.of with a directory that contains two * versions of the same module @@ -748,7 +740,7 @@ public class ModuleFinderTest { vs = mid.substring(i+1); } ModuleDescriptor.Builder builder - = ModuleDescriptor.module(mn).requires("java.base"); + = ModuleDescriptor.newModule(mn).requires("java.base"); if (vs != null) builder.version(vs); return builder.build(); diff --git a/jdk/test/java/lang/module/ModuleNamesTest.java b/jdk/test/java/lang/module/ModuleNamesTest.java index c0790eab202..afeadacec86 100644 --- a/jdk/test/java/lang/module/ModuleNamesTest.java +++ b/jdk/test/java/lang/module/ModuleNamesTest.java @@ -235,7 +235,7 @@ public class ModuleNamesTest { */ private Builder newBuilder(String mn) { return SharedSecrets.getJavaLangModuleAccess() - .newModuleBuilder(mn, false, false, false); + .newModuleBuilder(mn, false, Set.of()); } /** diff --git a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java index d956c249651..12e53b0f5fb 100644 --- a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java +++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java @@ -79,14 +79,52 @@ public class ModuleReaderTest { "java/lang/Object.class" }; + // resource names that should not be found in the base module + private static final String[] BAD_BASE_RESOURCES = { + "NotFound", + "java", + "/java", + "//java", + "java/", + "java/lang", + "/java/lang", + "//java/lang", + "java/lang/", + "java//lang", + "/java/lang/Object.class", + "//java/lang/Object.class", + "java/lang/Object.class/", + "java//lang//Object.class", + "./java/lang/Object.class", + "java/./lang/Object.class", + "java/lang/./Object.class", + "../java/lang/Object.class", + "java/../lang/Object.class", + "java/lang/../Object.class", + }; + // resources in test module (can't use module-info.class as a test // resource as it will be modified by the jmod tool) private static final String[] TEST_RESOURCES = { "p/Main.class" }; - // a resource that is not in the base or test module - private static final String NOT_A_RESOURCE = "NotAResource"; + // resource names that should not be found in the test module + private static final String[] BAD_TEST_RESOURCES = { + "NotFound", + "p", + "/p", + "//p", + "p/", + "/p/Main.class", + "//p/Main.class", + "p/Main.class/", + "p//Main.class", + "./p/Main.class", + "p/./Main.class", + "../p/Main.class", + "p/../p/Main.class" + }; @BeforeTest @@ -126,10 +164,11 @@ public class ModuleReaderTest { } // test "not found" - assertFalse(reader.find(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.open(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.read(NOT_A_RESOURCE).isPresent()); - + for (String name : BAD_BASE_RESOURCES) { + assertFalse(reader.find(name).isPresent()); + assertFalse(reader.open(name).isPresent()); + assertFalse(reader.read(name).isPresent()); + } // test nulls try { @@ -216,7 +255,7 @@ public class ModuleReaderTest { */ void test(Path mp) throws IOException { - ModuleFinder finder = new ModulePath(Runtime.version(), true, mp); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, mp); ModuleReference mref = finder.find(TEST_MODULE).get(); ModuleReader reader = mref.open(); @@ -236,9 +275,11 @@ public class ModuleReaderTest { } // test "not found" - assertFalse(reader.find(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.open(NOT_A_RESOURCE).isPresent()); - assertFalse(reader.read(NOT_A_RESOURCE).isPresent()); + for (String name : BAD_TEST_RESOURCES) { + assertFalse(reader.find(name).isPresent()); + assertFalse(reader.open(name).isPresent()); + assertFalse(reader.read(name).isPresent()); + } // test nulls try { diff --git a/jdk/test/java/lang/module/ModuleReferenceTest.java b/jdk/test/java/lang/module/ModuleReferenceTest.java index bf2db124de5..f3cbb28babd 100644 --- a/jdk/test/java/lang/module/ModuleReferenceTest.java +++ b/jdk/test/java/lang/module/ModuleReferenceTest.java @@ -31,6 +31,7 @@ import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; import java.net.URI; +import java.util.Set; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -49,10 +50,10 @@ public class ModuleReferenceTest { public void testBasic() throws Exception { ModuleDescriptor descriptor - = ModuleDescriptor.module("m") + = ModuleDescriptor.newModule("m") .exports("p") .exports("q") - .contains("p.internal") + .packages(Set.of("p.internal")) .build(); URI uri = URI.create("module:/m"); @@ -71,7 +72,7 @@ public class ModuleReferenceTest { public void testNullLocation() { ModuleDescriptor descriptor - = ModuleDescriptor.module("m") + = ModuleDescriptor.newModule("m") .exports("p") .build(); ModuleReference mref = newModuleReference(descriptor, null); diff --git a/jdk/test/java/lang/module/MultiReleaseJarTest.java b/jdk/test/java/lang/module/MultiReleaseJarTest.java index 7daddb11993..4c58e930b08 100644 --- a/jdk/test/java/lang/module/MultiReleaseJarTest.java +++ b/jdk/test/java/lang/module/MultiReleaseJarTest.java @@ -65,7 +65,7 @@ public class MultiReleaseJarTest { private static final String MODULE_INFO = "module-info.class"; - private static final int RELEASE = Runtime.version().major(); + private static final int VERSION = Runtime.version().major(); // are multi-release JARs enabled? private static final boolean MULTI_RELEASE; @@ -80,7 +80,7 @@ public class MultiReleaseJarTest { public void testBasic() throws Exception { String name = "m1"; - ModuleDescriptor descriptor = ModuleDescriptor.module(name) + ModuleDescriptor descriptor = ModuleDescriptor.newModule(name) .requires("java.base") .build(); @@ -88,8 +88,8 @@ public class MultiReleaseJarTest { .moduleInfo("module-info.class", descriptor) .resource("p/Main.class") .resource("p/Helper.class") - .resource("META-INF/versions/9/p/Helper.class") - .resource("META-INF/versions/9/p/internal/Helper9.class") + .resource("META-INF/versions/" + VERSION + "/p/Helper.class") + .resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class") .build(); // find the module @@ -117,12 +117,12 @@ public class MultiReleaseJarTest { public void testModuleInfoInVersionedSection() throws Exception { String name = "m1"; - ModuleDescriptor descriptor1 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor1 = ModuleDescriptor.newModule(name) .requires("java.base") .build(); // module descriptor for versioned section - ModuleDescriptor descriptor2 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor2 = ModuleDescriptor.newModule(name) .requires("java.base") .requires("jdk.unsupported") .build(); @@ -131,9 +131,9 @@ public class MultiReleaseJarTest { .moduleInfo(MODULE_INFO, descriptor1) .resource("p/Main.class") .resource("p/Helper.class") - .moduleInfo("META-INF/versions/9/" + MODULE_INFO, descriptor2) - .resource("META-INF/versions/9/p/Helper.class") - .resource("META-INF/versions/9/p/internal/Helper9.class") + .moduleInfo("META-INF/versions/" + VERSION + "/" + MODULE_INFO, descriptor2) + .resource("META-INF/versions/" + VERSION + "/p/Helper.class") + .resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class") .build(); // find the module @@ -161,8 +161,8 @@ public class MultiReleaseJarTest { Path jar = new JarBuilder(name) .resource("p/Main.class") .resource("p/Helper.class") - .resource("META-INF/versions/9/p/Helper.class") - .resource("META-INF/versions/9/p/internal/Helper9.class") + .resource("META-INF/versions/" + VERSION + "/p/Helper.class") + .resource("META-INF/versions/" + VERSION + "/p/internal/Helper.class") .build(); // find the module @@ -188,19 +188,19 @@ public class MultiReleaseJarTest { public void testModuleReader() throws Exception { String name = "m1"; - ModuleDescriptor descriptor1 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor1 = ModuleDescriptor.newModule(name) .requires("java.base") .build(); // module descriptor for versioned section - ModuleDescriptor descriptor2 = ModuleDescriptor.module(name) + ModuleDescriptor descriptor2 = ModuleDescriptor.newModule(name) .requires("java.base") .requires("jdk.unsupported") .build(); Path jar = new JarBuilder(name) .moduleInfo(MODULE_INFO, descriptor1) - .moduleInfo("META-INF/versions/9/" + MODULE_INFO, descriptor2) + .moduleInfo("META-INF/versions/" + VERSION + "/" + MODULE_INFO, descriptor2) .build(); // find the module @@ -243,7 +243,7 @@ public class MultiReleaseJarTest { String expectedTail = "!/"; if (MULTI_RELEASE) - expectedTail += "META-INF/versions/" + RELEASE + "/"; + expectedTail += "META-INF/versions/" + VERSION + "/"; expectedTail += MODULE_INFO; assertTrue(uri.toString().endsWith(expectedTail)); diff --git a/jdk/test/java/lang/reflect/AccessibleObject/CanAccessTest.java b/jdk/test/java/lang/reflect/AccessibleObject/CanAccessTest.java new file mode 100644 index 00000000000..c73eb795b26 --- /dev/null +++ b/jdk/test/java/lang/reflect/AccessibleObject/CanAccessTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 + * @build CanAccessTest + * @modules java.base/jdk.internal.misc:+open + * @run testng CanAccessTest + * @summary Test AccessibleObject::canAccess method + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.security.SecureClassLoader; + +import jdk.internal.misc.Unsafe; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class CanAccessTest { + private static Unsafe INSTANCE = Unsafe.getUnsafe(); + + /** + * null object parameter for Constructor + */ + public void testConstructor() throws Exception { + Constructor ctor = Unsafe.class.getDeclaredConstructor(); + assertFalse(ctor.canAccess(null)); + assertTrue(ctor.trySetAccessible()); + + try { + // non-null object parameter + ctor.canAccess(INSTANCE); + assertTrue(false); + } catch (IllegalArgumentException expected) {} + } + + /** + * Test protected constructors + */ + public void testProtectedConstructor() throws Exception { + TestLoader.testProtectedConstructorNonOpenedPackage(); + + Constructor ctor = TestLoader.class.getDeclaredConstructor(); + assertTrue(ctor.canAccess(null)); + } + + /** + * null object parameter for static members + */ + public void testStaticMember() throws Exception { + Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); + assertFalse(m.canAccess(null)); + assertTrue(m.trySetAccessible()); + + try { + // non-null object parameter + m.canAccess(INSTANCE); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + /** + * Test protected static + */ + public void testProtectedStatic() throws Exception { + Method m = TestLoader.testProtectedStatic(); + assertFalse(m.canAccess(null)); + } + + /** + * the specified object must be an instance of the declaring class + * for instance members + */ + public void testInstanceMethod() throws Exception { + Method m = Unsafe.class.getDeclaredMethod("addressSize0"); + assertFalse(m.canAccess(INSTANCE)); + + try { + m.canAccess(null); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + /** + * the specified object must be an instance of the declaring class + * for instance members + */ + public void testInvalidInstanceObject() throws Exception { + Class clazz = Class.forName("sun.security.x509.X500Name"); + Method m = clazz.getDeclaredMethod("size"); + + try { + m.canAccess(INSTANCE); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + + static class TestLoader extends SecureClassLoader { + public static Method testProtectedStatic() throws Exception { + Method m = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable"); + assertTrue(m.canAccess(null)); + return m; + } + + protected TestLoader() throws Exception { + Constructor ctor = SecureClassLoader.class.getDeclaredConstructor(); + assertFalse(ctor.canAccess(null)); + assertFalse(ctor.trySetAccessible()); + } + + public static void testProtectedConstructorNonOpenedPackage() throws Exception { + new TestLoader(); + } + } +} diff --git a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java index da5d264b1fd..3e2bf3911c7 100644 --- a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java +++ b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java @@ -30,7 +30,6 @@ * @summary Test java.lang.reflect.AccessibleObject with modules */ -import java.lang.module.ModuleDescriptor; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; diff --git a/jdk/test/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java b/jdk/test/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java new file mode 100644 index 00000000000..340e7d00613 --- /dev/null +++ b/jdk/test/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 + * @build TrySetAccessibleTest + * @modules java.base/java.lang:open + * java.base/jdk.internal.perf + * java.base/jdk.internal.misc:+open + * @run testng TrySetAccessibleTest + * @summary Test AccessibleObject::trySetAccessible method + */ + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import jdk.internal.misc.Unsafe; +import jdk.internal.perf.Perf; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class TrySetAccessibleTest { + /** + * Invoke a private constructor on a public class in an exported package + */ + public void testPrivateConstructorInExportedPackage() throws Exception { + Constructor ctor = Perf.class.getDeclaredConstructor(); + + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(ctor.trySetAccessible()); + assertFalse(ctor.canAccess(null)); + } + + /** + * Invoke a private constructor on a public class in an open package + */ + public void testPrivateConstructorInOpenedPackage() throws Exception { + Constructor ctor = Unsafe.class.getDeclaredConstructor(); + + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertTrue(ctor.trySetAccessible()); + assertTrue(ctor.canAccess(null)); + Unsafe unsafe = (Unsafe) ctor.newInstance(); + } + + /** + * Invoke a private method on a public class in an exported package + */ + public void testPrivateMethodInExportedPackage() throws Exception { + Method m = Perf.class.getDeclaredMethod("getBytes", String.class); + try { + m.invoke(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(m.trySetAccessible()); + assertFalse(m.canAccess(null)); + } + + + /** + * Invoke a private method on a public class in an open package + */ + public void testPrivateMethodInOpenedPackage() throws Exception { + Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); + assertFalse(m.canAccess(null)); + + try { + m.invoke(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertTrue(m.trySetAccessible()); + assertTrue(m.canAccess(null)); + try { + m.invoke(null); + assertTrue(false); + } catch (InvocationTargetException e) { + // thrown by throwIllegalAccessError + assertTrue(e.getCause() instanceof IllegalAccessError); + } + } + + /** + * Invoke a private method on a public class in an exported package + */ + public void testPrivateFieldInExportedPackage() throws Exception { + Field f = Perf.class.getDeclaredField("instance"); + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(f.trySetAccessible()); + assertFalse(f.canAccess(null)); + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) {} + } + + /** + * Access a private field in a public class that is an exported package + */ + public void testPrivateFieldInOpenedPackage() throws Exception { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertTrue(f.trySetAccessible()); + assertTrue(f.canAccess(null)); + Unsafe unsafe = (Unsafe) f.get(null); + } + + + /** + * Invoke a public constructor on a public class in a non-exported package + */ + public void testPublicConstructorInNonExportedPackage() throws Exception { + Class clazz = Class.forName("sun.security.x509.X500Name"); + Constructor ctor = clazz.getConstructor(String.class); + + try { + ctor.newInstance("cn=duke"); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(ctor.trySetAccessible()); + assertFalse(ctor.canAccess(null)); + assertTrue(ctor.trySetAccessible() == ctor.isAccessible()); + } + + + /** + * Access a public field in a public class that in a non-exported package + */ + public void testPublicFieldInNonExportedPackage() throws Exception { + Class clazz = Class.forName("sun.security.x509.X500Name"); + Field f = clazz.getField("SERIALNUMBER_OID"); + + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + assertFalse(f.trySetAccessible()); + assertFalse(f.canAccess(null)); + } + + + /** + * Test that the Class constructor cannot be make accessible. + */ + public void testJavaLangClass() throws Exception { + + // non-public constructor + Constructor ctor + = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class); + AccessibleObject[] ctors = { ctor }; + + assertFalse(ctor.trySetAccessible()); + assertFalse(ctor.canAccess(null)); + } + +} diff --git a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java index 8f14171ce87..1bb04d9c12e 100644 --- a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java +++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /** * @test * @library /lib/testlibrary + * @modules java.base/jdk.internal.misc * @build BasicLayerTest ModuleUtils * @compile layertest/Test.java * @run testng BasicLayerTest @@ -43,12 +44,22 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import jdk.internal.misc.SharedSecrets; import org.testng.annotations.Test; import static org.testng.Assert.*; @Test public class BasicLayerTest { + /** + * Creates a "non-strict" builder for building a module. This allows the + * test the create ModuleDescriptor objects that do not require java.base. + */ + private static ModuleDescriptor.Builder newBuilder(String mn) { + return SharedSecrets.getJavaLangModuleAccess() + .newModuleBuilder(mn, false, Set.of()); + } + /** * Exercise Layer.empty() */ @@ -109,25 +120,22 @@ public class BasicLayerTest { * Exercise Layer defineModules, created with empty layer as parent */ public void testLayerOnEmpty() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .exports("p1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m3") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); // map each module to its own class loader for this test ClassLoader loader1 = new ClassLoader() { }; @@ -191,15 +199,13 @@ public class BasicLayerTest { * Exercise Layer defineModules, created with boot layer as parent */ public void testLayerOnBoot() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .requires("java.base") .exports("p1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires("java.base") .build(); @@ -207,7 +213,7 @@ public class BasicLayerTest { = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration parent = Layer.boot().configuration(); - Configuration cf = resolveRequires(parent, finder, "m1"); + Configuration cf = resolve(parent, finder, "m1"); ClassLoader loader = new ClassLoader() { }; @@ -256,21 +262,19 @@ public class BasicLayerTest { * have the same module-private package. */ public void testPackageContainedInSelfAndOther() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") - .contains("p") + .packages(Set.of("p")) .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") - .contains("p") + ModuleDescriptor descriptor2 = newBuilder("m2") + .packages(Set.of("p")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); assertTrue(cf.modules().size() == 2); // one loader per module, should be okay @@ -292,22 +296,18 @@ public class BasicLayerTest { public void testSameExportInPartitionedGraph() { // m1 reads m2, m2 exports p to m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p", Set.of("m1")) .build(); // m3 reads m4, m4 exports p to m3 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m4") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .exports("p", Set.of("m3")) .build(); @@ -317,7 +317,7 @@ public class BasicLayerTest { descriptor3, descriptor4); - Configuration cf = resolveRequires(finder, "m1", "m3"); + Configuration cf = resolve(finder, "m1", "m3"); assertTrue(cf.modules().size() == 4); // one loader per module @@ -353,16 +353,15 @@ public class BasicLayerTest { ModuleDescriptor base = Object.class.getModule().getDescriptor(); assertTrue(base.packages().contains("sun.launcher")); - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor = newBuilder("m1") .requires("java.base") - .contains("sun.launcher") + .packages(Set.of("sun.launcher")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); assertTrue(cf.modules().size() == 1); ClassLoader loader = new ClassLoader() { }; @@ -382,18 +381,16 @@ public class BasicLayerTest { // cf1: m1 and m2, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -401,14 +398,13 @@ public class BasicLayerTest { // cf2: m3, m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -456,13 +452,11 @@ public class BasicLayerTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -470,19 +464,17 @@ public class BasicLayerTest { // cf2: m2, m3: m2 requires transitive m1, m3 requires m2 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); - Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + Configuration cf2 = resolve(cf1, finder2, "m3"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -527,13 +519,11 @@ public class BasicLayerTest { // cf1: m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .build(); + ModuleDescriptor descriptor1 = newBuilder("m1").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); - Configuration cf1 = resolveRequires(finder1, "m1"); + Configuration cf1 = resolve(finder1, "m1"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -541,14 +531,13 @@ public class BasicLayerTest { // cf2: m2 requires transitive m1 - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); - Configuration cf2 = resolveRequires(cf1, finder2, "m2"); + Configuration cf2 = resolve(cf1, finder2, "m2"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -556,14 +545,13 @@ public class BasicLayerTest { // cf3: m3 requires m2 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); - Configuration cf3 = resolveRequires(cf2, finder3, "m3"); + Configuration cf3 = resolve(cf2, finder3, "m3"); ClassLoader cl3 = new ClassLoader() { }; Layer layer3 = layer2.defineModules(cf3, mn -> cl3); @@ -610,18 +598,16 @@ public class BasicLayerTest { // cf1: m1, m2 requires transitive m1 - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); - ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); - Configuration cf1 = resolveRequires(finder1, "m2"); + Configuration cf1 = resolve(finder1, "m2"); ClassLoader cl1 = new ClassLoader() { }; Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); @@ -629,20 +615,18 @@ public class BasicLayerTest { // cf2: m3 requires transitive m2, m4 requires m3 - ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3") + ModuleDescriptor descriptor3 = newBuilder("m3") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m2") .build(); - ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4") + ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m3") .build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4"); + Configuration cf2 = resolve(cf1, finder2, "m3", "m4"); ClassLoader cl2 = new ClassLoader() { }; Layer layer2 = layer1.defineModules(cf2, mn -> cl2); @@ -693,8 +677,7 @@ public class BasicLayerTest { @Test(expectedExceptions = { LayerInstantiationException.class }) public void testModuleAlreadyDefinedToLoader() { - ModuleDescriptor md - = ModuleDescriptor.module("m") + ModuleDescriptor md = newBuilder("m") .requires("java.base") .build(); @@ -702,7 +685,7 @@ public class BasicLayerTest { Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); ClassLoader loader = new ClassLoader() { }; @@ -722,15 +705,13 @@ public class BasicLayerTest { @Test(expectedExceptions = { LayerInstantiationException.class }) public void testPackageAlreadyInNamedModule() { - ModuleDescriptor md1 - = ModuleDescriptor.module("m1") - .contains("p") + ModuleDescriptor md1 = newBuilder("m1") + .packages(Set.of("p")) .requires("java.base") .build(); - ModuleDescriptor md2 - = ModuleDescriptor.module("m2") - .contains("p") + ModuleDescriptor md2 = newBuilder("m2") + .packages(Set.of("p")) .requires("java.base") .build(); @@ -742,13 +723,13 @@ public class BasicLayerTest { Configuration parent = Layer.boot().configuration(); - Configuration cf1 = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + Configuration cf1 = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer1 = Layer.boot().defineModules(cf1, mn -> loader); // attempt to define m2 containing package p to class loader - Configuration cf2 = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m2")); + Configuration cf2 = parent.resolve(finder, ModuleFinder.of(), Set.of("m2")); // should throw exception because p already in m1 Layer layer2 = Layer.boot().defineModules(cf2, mn -> loader); @@ -767,16 +748,15 @@ public class BasicLayerTest { Class c = layertest.Test.class; assertFalse(c.getModule().isNamed()); // in unnamed module - ModuleDescriptor md - = ModuleDescriptor.module("m") - .contains(c.getPackageName()) + ModuleDescriptor md = newBuilder("m") + .packages(Set.of(c.getPackageName())) .requires("java.base") .build(); ModuleFinder finder = ModuleUtils.finderOf(md); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m")); Layer.boot().defineModules(cf, mn -> c.getClassLoader()); } @@ -786,8 +766,7 @@ public class BasicLayerTest { * Attempt to create a Layer with a module named "java.base". */ public void testLayerWithJavaBase() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("java.base") + ModuleDescriptor descriptor = newBuilder("java.base") .exports("java.lang") .build(); @@ -795,7 +774,7 @@ public class BasicLayerTest { Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("java.base")); + .resolve(finder, ModuleFinder.of(), Set.of("java.base")); assertTrue(cf.modules().size() == 1); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -824,16 +803,15 @@ public class BasicLayerTest { */ @Test(enabled = false) public void testLayerWithJavaPackage() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("foo") - .contains("java.foo") + ModuleDescriptor descriptor = newBuilder("foo") + .packages(Set.of("java.foo")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("foo")); + .resolve(finder, ModuleFinder.of(), Set.of("foo")); assertTrue(cf.modules().size() == 1); ClassLoader pcl = ClassLoader.getPlatformClassLoader(); @@ -870,15 +848,14 @@ public class BasicLayerTest { */ @Test(expectedExceptions = { LayerInstantiationException.class }) public void testLayerWithBootLoader() { - ModuleDescriptor descriptor - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor = newBuilder("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + .resolve(finder, ModuleFinder.of(), Set.of("m1")); assertTrue(cf.modules().size() == 1); Layer.boot().defineModules(cf, mn -> null ); @@ -891,15 +868,14 @@ public class BasicLayerTest { @Test(expectedExceptions = { IllegalArgumentException.class }) public void testIncorrectParent1() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .requires("java.base") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); Configuration parent = Layer.boot().configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), Set.of("m1")); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("m1")); ClassLoader loader = new ClassLoader() { }; Layer.empty().defineModules(cf, mn -> loader); @@ -912,13 +888,12 @@ public class BasicLayerTest { @Test(expectedExceptions = { IllegalArgumentException.class }) public void testIncorrectParent2() { - ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") + ModuleDescriptor descriptor1 = newBuilder("m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); - Configuration cf = resolveRequires(finder, "m1"); + Configuration cf = resolve(finder, "m1"); ClassLoader loader = new ClassLoader() { }; Layer.boot().defineModules(cf, mn -> loader); @@ -935,7 +910,7 @@ public class BasicLayerTest { @Test(expectedExceptions = { NullPointerException.class }) public void testCreateWithNull2() { - Configuration cf = resolveRequires(Layer.boot().configuration(), ModuleFinder.of()); + Configuration cf = resolve(Layer.boot().configuration(), ModuleFinder.of()); Layer.boot().defineModules(cf, null); } @@ -975,14 +950,14 @@ public class BasicLayerTest { * Resolve the given modules, by name, and returns the resulting * Configuration. */ - private static Configuration resolveRequires(Configuration cf, - ModuleFinder finder, - String... roots) { - return cf.resolveRequires(finder, ModuleFinder.of(), Set.of(roots)); + private static Configuration resolve(Configuration cf, + ModuleFinder finder, + String... roots) { + return cf.resolve(finder, ModuleFinder.of(), Set.of(roots)); } - private static Configuration resolveRequires(ModuleFinder finder, - String... roots) { - return resolveRequires(Configuration.empty(), finder, roots); + private static Configuration resolve(ModuleFinder finder, + String... roots) { + return resolve(Configuration.empty(), finder, roots); } } diff --git a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java index 23c7d06d15d..ac6c035c297 100644 --- a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java +++ b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java @@ -81,7 +81,7 @@ public class LayerAndLoadersTest { */ public void testWithOneLoader() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -110,7 +110,7 @@ public class LayerAndLoadersTest { */ public void testWithManyLoaders() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -145,7 +145,7 @@ public class LayerAndLoadersTest { */ public void testServicesWithOneLoader() throws Exception { - Configuration cf = resolveRequiresAndUses("m1"); + Configuration cf = resolveAndBind("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -186,7 +186,7 @@ public class LayerAndLoadersTest { */ public void testServicesWithManyLoaders() throws Exception { - Configuration cf = resolveRequiresAndUses("m1"); + Configuration cf = resolveAndBind("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -233,7 +233,7 @@ public class LayerAndLoadersTest { */ public void testDelegationToParent() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader parent = this.getClass().getClassLoader(); String cn = this.getClass().getName(); @@ -267,16 +267,16 @@ public class LayerAndLoadersTest { public void testOverlappingPackages() { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").exports("p").build(); + = ModuleDescriptor.newModule("m1").exports("p").build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").exports("p").build(); + = ModuleDescriptor.newModule("m2").exports("p").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration cf = Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("m1", "m2")); + .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); // cannot define both module m1 and m2 to the same class loader try { @@ -301,29 +301,29 @@ public class LayerAndLoadersTest { public void testSplitDelegation() { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1").exports("p").build(); + = ModuleDescriptor.newModule("m1").exports("p").build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2").exports("p").build(); + = ModuleDescriptor.newModule("m2").exports("p").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration cf1 = Layer.boot() .configuration() - .resolveRequires(finder1, ModuleFinder.of(), Set.of("m1", "m2")); + .resolve(finder1, ModuleFinder.of(), Set.of("m1", "m2")); Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); checkLayer(layer1, "m1", "m2"); ModuleDescriptor descriptor3 - = ModuleDescriptor.module("m3").requires("m1").build(); + = ModuleDescriptor.newModule("m3").requires("m1").build(); ModuleDescriptor descriptor4 - = ModuleDescriptor.module("m4").requires("m2").build(); + = ModuleDescriptor.newModule("m4").requires("m2").build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); - Configuration cf2 = cf1.resolveRequires(finder2, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder2, ModuleFinder.of(), Set.of("m3", "m4")); // package p cannot be supplied by two class loaders @@ -349,13 +349,13 @@ public class LayerAndLoadersTest { */ public void testOverriding1() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); @@ -398,13 +398,13 @@ public class LayerAndLoadersTest { */ public void testOverriding2() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = ModuleFinder.of(MODS_DIR); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); @@ -492,14 +492,14 @@ public class LayerAndLoadersTest { */ public void testOverriding3() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = finderFor("m1", "m3"); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); @@ -529,14 +529,14 @@ public class LayerAndLoadersTest { */ public void testOverriding4() throws Exception { - Configuration cf1 = resolveRequires("m1"); + Configuration cf1 = resolve("m1"); Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); checkLayer(layer1, "m1", "m2", "m3"); ModuleFinder finder = finderFor("m1", "m3"); - Configuration cf2 = cf1.resolveRequires(finder, ModuleFinder.of(), + Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), Set.of("m1")); Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); @@ -577,7 +577,7 @@ public class LayerAndLoadersTest { * Layer.defineModulesWithOneLoader. */ public void testResourcesOneLoader() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); ClassLoader loader = layer.findLoader("m1"); @@ -589,7 +589,7 @@ public class LayerAndLoadersTest { * Layer.defineModulesWithOneLoader. */ public void testResourcesManyLoaders() throws Exception { - Configuration cf = resolveRequires("m1"); + Configuration cf = resolve("m1"); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); ClassLoader loader = layer.findLoader("m1"); @@ -621,22 +621,22 @@ public class LayerAndLoadersTest { * Resolve the given modules, by name, and returns the resulting * Configuration. */ - private static Configuration resolveRequires(String... roots) { + private static Configuration resolve(String... roots) { ModuleFinder finder = ModuleFinder.of(MODS_DIR); return Layer.boot() .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of(roots)); + .resolve(finder, ModuleFinder.of(), Set.of(roots)); } /** * Resolve the given modules, by name, and returns the resulting * Configuration. */ - private static Configuration resolveRequiresAndUses(String... roots) { + private static Configuration resolveAndBind(String... roots) { ModuleFinder finder = ModuleFinder.of(MODS_DIR); return Layer.boot() .configuration() - .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(roots)); + .resolveAndBind(finder, ModuleFinder.of(), Set.of(roots)); } diff --git a/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java index 6582e493c07..4e4a0dbd5bd 100644 --- a/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java +++ b/jdk/test/java/lang/reflect/Layer/LayerControllerTest.java @@ -50,22 +50,22 @@ public class LayerControllerTest { */ private Layer.Controller createTestLayer() { ModuleDescriptor descriptor1 - = ModuleDescriptor.module("m1") - .contains("p1") + = ModuleDescriptor.newModule("m1") + .packages(Set.of("p1")) .requires("java.base") .build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.module("m2") + = ModuleDescriptor.newModule("m2") .requires("java.base") - .contains("p2") + .packages(Set.of("p2")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); Layer bootLayer = Layer.boot(); Configuration cf = bootLayer.configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of("m1", "m2")); + .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); ClassLoader scl = ClassLoader.getSystemClassLoader(); @@ -193,4 +193,4 @@ public class LayerControllerTest { assertTrue(false); } catch (NullPointerException expected) { } } -} \ No newline at end of file +} diff --git a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java index 0390698b282..d30a0c07779 100644 --- a/jdk/test/java/lang/reflect/Module/AnnotationsTest.java +++ b/jdk/test/java/lang/reflect/Module/AnnotationsTest.java @@ -144,7 +144,7 @@ public class AnnotationsTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer.configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of(name)); + .resolve(finder, ModuleFinder.of(), Set.of(name)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); diff --git a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java index bafa57ba3a8..90fb62b4a2e 100644 --- a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java +++ b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,10 @@ import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ResolvedModule; import java.lang.reflect.Layer; import java.lang.reflect.Module; +import java.nio.file.spi.FileSystemProvider; // service type in java.base import java.util.function.Predicate; import java.util.stream.Stream; +import javax.print.PrintServiceLookup; // service type in java.desktop import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -170,6 +172,14 @@ public class BasicModuleTest { // canRead assertTrue(base.canRead(base)); + assertFalse(base.canRead(thisModule)); + + // addReads + try { + base.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.canRead(thisModule)); // isExported assertTrue(base.isExported("java.lang")); @@ -182,6 +192,18 @@ public class BasicModuleTest { assertFalse(base.isExported("java.wombat", thisModule)); assertFalse(base.isExported("java.wombat", base)); + // addExports + try { + base.addExports("java.lang", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + base.addExports("jdk.internal.misc", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.isExported("jdk.internal.misc")); + assertFalse(base.isExported("jdk.internal.misc", thisModule)); + // isOpen assertFalse(base.isOpen("java.lang")); assertFalse(base.isOpen("java.lang", thisModule)); @@ -192,6 +214,29 @@ public class BasicModuleTest { assertFalse(base.isOpen("java.wombat")); assertFalse(base.isOpen("java.wombat", thisModule)); assertFalse(base.isOpen("java.wombat", base)); + + // addOpens + try { + base.addOpens("jdk.internal.misc", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.isOpen("jdk.internal.misc")); + assertFalse(base.isOpen("jdk.internal.misc", thisModule)); + + // canUse + assertTrue(base.canUse(FileSystemProvider.class)); + assertFalse(base.canUse(Thread.class)); + + // addUses + try { + base.addUses(FileSystemProvider.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + base.addUses(Thread.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(base.canUse(Thread.class)); } @@ -226,26 +271,68 @@ public class BasicModuleTest { assertTrue(desktop.canRead(base)); assertTrue(desktop.canRead(xml)); + // addReads + try { + desktop.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.canRead(thisModule)); + // isExported assertTrue(desktop.isExported("java.awt")); assertTrue(desktop.isExported("java.awt", thisModule)); + assertFalse(desktop.isExported("sun.awt")); + assertFalse(desktop.isExported("sun.awt", thisModule)); + assertTrue(desktop.isExported("sun.awt", desktop)); assertFalse(desktop.isExported("java.wombat")); assertFalse(desktop.isExported("java.wombat", thisModule)); + assertFalse(desktop.isExported("java.wombat", base)); + + // addExports + try { + desktop.addExports("java.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + desktop.addExports("sun.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.isExported("sun.awt")); + assertFalse(desktop.isExported("sun.awt", thisModule)); + + // isOpen + assertFalse(desktop.isOpen("java.awt")); + assertFalse(desktop.isOpen("java.awt", thisModule)); + assertTrue(desktop.isOpen("java.awt", desktop)); + assertFalse(desktop.isOpen("sun.awt")); + assertFalse(desktop.isOpen("sun.awt", thisModule)); + assertTrue(desktop.isOpen("sun.awt", desktop)); + assertFalse(desktop.isOpen("java.wombat")); + assertFalse(desktop.isOpen("java.wombat", thisModule)); + assertFalse(desktop.isOpen("java.wombat", desktop)); + + // addOpens + try { + base.addOpens("sun.awt", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.isOpen("sun.awt")); + assertFalse(desktop.isOpen("sun.awt", thisModule)); + + // canUse + assertTrue(base.canUse(FileSystemProvider.class)); + assertFalse(base.canUse(Thread.class)); + + // addUses + try { + desktop.addUses(PrintServiceLookup.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + try { + desktop.addUses(Thread.class); + assertTrue(false); + } catch (IllegalCallerException expected) { } + assertFalse(desktop.canUse(Thread.class)); } - - @Test(expectedExceptions = { NullPointerException.class }) - public void testIsExportedNull() { - Module thisModule = this.getClass().getModule(); - thisModule.isExported(null, thisModule); - } - - - @Test(expectedExceptions = { NullPointerException.class }) - public void testIsExportedToNull() { - Module thisModule = this.getClass().getModule(); - thisModule.isExported("", null); - } - - } diff --git a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java index dfb6b760f10..794ebf00e44 100644 --- a/jdk/test/java/lang/reflect/Module/WithSecurityManager.java +++ b/jdk/test/java/lang/reflect/Module/WithSecurityManager.java @@ -126,7 +126,7 @@ public class WithSecurityManager { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequires(finder, ModuleFinder.of(), Set.of(ANOTHER_MODULE)); + .resolve(finder, ModuleFinder.of(), Set.of(ANOTHER_MODULE)); Layer layer = bootLayer.defineModulesWithOneLoader(cf, null); Optional om = layer.findModule(mn); diff --git a/jdk/test/java/lang/reflect/Module/addXXX/Driver.java b/jdk/test/java/lang/reflect/Module/addXXX/Driver.java new file mode 100644 index 00000000000..0daf09ffe2a --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/Driver.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 + * @build test/* m1/* m2/* m3/* m4/* + * @run testng/othervm test/test.Main + * @summary Basic test case for Module::addXXX methods + */ diff --git a/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFound/modulesourcepath/m1x/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m1/module-info.java similarity index 92% rename from langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFound/modulesourcepath/m1x/module-info.java rename to jdk/test/java/lang/reflect/Module/addXXX/m1/module-info.java index 763338727cd..a34a266ef57 100644 --- a/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFound/modulesourcepath/m1x/module-info.java +++ b/jdk/test/java/lang/reflect/Module/addXXX/m1/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,7 +20,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - -module m1x { +module m1 { exports p1; } diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m1/p1/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m1/p1/C.java new file mode 100644 index 00000000000..86357613dc5 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m1/p1/C.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 p1; + +public class C { + public C() { } +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m2/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m2/module-info.java new file mode 100644 index 00000000000..918d72aac64 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m2/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +module m2 { + exports p2; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/C.java new file mode 100644 index 00000000000..6a87a2eba87 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/C.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 p2; + +import java.lang.reflect.Module; + +public class C { + + public static void export(String pn, Module m) { + C.class.getModule().addExports(pn, m); + } +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java new file mode 100644 index 00000000000..b3009610032 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 p2.internal; + +public class C { +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m3/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m3/module-info.java new file mode 100644 index 00000000000..75d5c1664be --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m3/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +module m3 { + exports p3 to test; + opens p3 to test; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m3/p3/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m3/p3/C.java new file mode 100644 index 00000000000..c1013ce13db --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m3/p3/C.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 p3; + +public class C { +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m4/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/m4/module-info.java new file mode 100644 index 00000000000..313ea941316 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m4/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +module m4 { + exports p4; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/m4/p4/C.java b/jdk/test/java/lang/reflect/Module/addXXX/m4/p4/C.java new file mode 100644 index 00000000000..a5e9a127f8c --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/m4/p4/C.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 p4; + +import java.lang.reflect.Constructor; + +public class C { + public static Object tryNewInstance(Class clazz) throws Exception { + Constructor ctor = clazz.getDeclaredConstructor(); + return ctor.newInstance(); + } +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/module-info.java b/jdk/test/java/lang/reflect/Module/addXXX/test/module-info.java new file mode 100644 index 00000000000..ebfab744dec --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/module-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +module test { + exports test to testng; + + requires m2; + requires m3; + requires m4; + requires testng; +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/test/C.java b/jdk/test/java/lang/reflect/Module/addXXX/test/test/C.java new file mode 100644 index 00000000000..e031680445c --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/test/C.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 test; + +public class C { } diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/test/Main.java b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Main.java new file mode 100644 index 00000000000..924f0a87de4 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Main.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 test; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.Module; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * Basic test case for Module::addXXXX methods + */ + +@Test +public class Main { + + /** + * Test Module::addReads + * + * module test { } + * + * module m1 { + * exports p1; + * } + */ + public void testAddReads() throws Throwable { + Module thisModule = Main.class.getModule(); + Class clazz = Class.forName("p1.C"); + Module m1 = clazz.getModule(); + + // test does not read m1 + assertFalse(thisModule.canRead(m1)); + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class); + try { + lookup.findConstructor(clazz, mt); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // update test to read m1 + Module result = thisModule.addReads(m1); + assertTrue(result== thisModule); + assertTrue(thisModule.canRead(m1)); + MethodHandle mh = lookup.findConstructor(clazz, mt); + Object obj = mh.invoke(); + + // attempt to update m1 to read test + try { + m1.addReads(thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + + /** + * Test Module::addExports + * + * module test { + * requires m2; + * } + * module m2 { + * exports p2; + * contains package p2.internal; + * } + */ + public void testAddExports() throws Exception { + Module thisModule = Main.class.getModule(); + Module m2 = p2.C.class.getModule(); + Class targetClass = Class.forName("p2.internal.C"); + String p2Internal = targetClass.getPackageName(); + assertTrue(targetClass.getModule() == m2); + + // m2 does not export p2.internal to test + assertFalse(m2.isExported(p2Internal, thisModule)); + Constructor ctor = targetClass.getDeclaredConstructor(); + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // update m2 to export p2.internal to test + p2.C.export(p2Internal, thisModule); + assertTrue(m2.isExported(p2Internal, thisModule)); + ctor.newInstance(); // should succeed + + // attempt to update m2 to export a package to test + try { + m2.addExports("p2.other", thisModule); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + /** + * Test Module::addOpens + * + * module test { + * requires m3; + * requires m4; + * } + * + * module m3 { + * exports p3 to test; + * opens p3 to test; + * } + * + * module m4 { + * exports p4; + * } + */ + public void testAddOpens() throws Exception { + Module thisModule = Main.class.getModule(); + Module m3 = p3.C.class.getModule(); + Module m4 = p4.C.class.getModule(); + + // test does not open package test to m4 + assertFalse(thisModule.isOpen("test", m4)); + try { + p4.C.tryNewInstance(test.C.class); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + // open test to m4 + thisModule.addOpens("test", m4); + p4.C.tryNewInstance(test.C.class); // should succeed + + + // m3 does not open p3 to m4 + assertFalse(m3.isOpen("p3", m4)); + try { + p4.C.tryNewInstance(p3.C.class); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + + // m3 opens p3 to test => test allowed to open m3/p3 to m4 + assertTrue(m3.isOpen("p3", thisModule)); + m3.addOpens("p3", m4); + assertTrue(m3.isOpen("p3", m4)); + p4.C.tryNewInstance(p3.C.class); // should succeed + + + // attempt to update m4 to open package to m3 + try { + m4.addOpens("p4", m3); + assertTrue(false); + } catch (IllegalCallerException expected) { } + } + + + /** + * Test Module::addUses + */ + public void testAddUses() { + Module thisModule = Main.class.getModule(); + + assertFalse(thisModule.canUse(Service.class)); + try { + ServiceLoader.load(Service.class); + assertTrue(false); + } catch (ServiceConfigurationError expected) { } + + Module result = thisModule.addUses(Service.class); + assertTrue(result== thisModule); + + assertTrue(thisModule.canUse(Service.class)); + ServiceLoader.load(Service.class); // no exception + } + +} diff --git a/jdk/test/java/lang/reflect/Module/addXXX/test/test/Service.java b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Service.java new file mode 100644 index 00000000000..9fd5b8d862a --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/addXXX/test/test/Service.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 test; + +/** + * Simple service type + */ +public interface Service { } diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java b/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java index 55e11f1b3ec..3ef48cd79fa 100644 --- a/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java +++ b/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java @@ -91,7 +91,7 @@ public class ProxyClassAccessTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, modules); + .resolveAndBind(ModuleFinder.of(), finder, modules); ClassLoader parentLoader = this.getClass().getClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, parentLoader); diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java b/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java index 5b04c93596b..767afd23323 100644 --- a/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java +++ b/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java @@ -79,7 +79,7 @@ public class ProxyLayerTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, Arrays.asList(modules)); + .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); @@ -113,7 +113,7 @@ public class ProxyLayerTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, Arrays.asList(modules)); + .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); @@ -143,7 +143,7 @@ public class ProxyLayerTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer .configuration() - .resolveRequiresAndUses(ModuleFinder.of(), finder, Arrays.asList(modules)); + .resolveAndBind(ModuleFinder.of(), finder, Arrays.asList(modules)); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); diff --git a/jdk/test/java/net/httpclient/security/Driver.java b/jdk/test/java/net/httpclient/security/Driver.java index 64b56084d41..5b58757adc3 100644 --- a/jdk/test/java/net/httpclient/security/Driver.java +++ b/jdk/test/java/net/httpclient/security/Driver.java @@ -127,6 +127,7 @@ public class Driver { cmd.add("-Dtest.src=" + testSrc); cmd.add("-Dtest.classes=" + testClasses); cmd.add("-Djava.security.manager"); + cmd.add("--add-modules=jdk.incubator.httpclient"); cmd.add("-Djava.security.policy=" + testSrc + sep + policy); cmd.add("-Dport.number=" + Integer.toString(Utils.getFreePort())); cmd.add("-Dport.number1=" + Integer.toString(Utils.getFreePort())); diff --git a/jdk/test/java/nio/channels/FileChannel/Transfer.java b/jdk/test/java/nio/channels/FileChannel/Transfer.java index 04a0f3251b2..b05fffdb869 100644 --- a/jdk/test/java/nio/channels/FileChannel/Transfer.java +++ b/jdk/test/java/nio/channels/FileChannel/Transfer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,43 +24,53 @@ /* @test * @bug 4434723 4482726 4559072 4638365 4795550 5081340 5103988 6253145 * 6984545 - * @summary Test FileChannel.transferFrom and transferTo + * @summary Test FileChannel.transferFrom and transferTo (use -Dseed=X to set PRNG seed) * @library .. + * @library /lib/testlibrary/ + * @build jdk.testlibrary.* + * @run testng Transfer * @key randomness */ -import java.io.*; -import java.net.*; -import java.nio.*; -import java.nio.channels.*; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintStream; +import java.io.RandomAccessFile; +import java.io.Reader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.NonReadableChannelException; +import java.nio.channels.Pipe; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; import java.nio.channels.spi.SelectorProvider; import java.nio.file.StandardOpenOption; import java.nio.file.FileAlreadyExistsException; import java.util.Random; +import java.util.concurrent.TimeUnit; +import jdk.testlibrary.RandomFactory; + +import org.testng.annotations.Test; public class Transfer { - private static Random generator = new Random(); + private static Random generator = RandomFactory.getRandom(); + private static PrintStream err = System.err; + private static PrintStream out = System.out; - private static int[] testSizes = { - 0, 10, 1023, 1024, 1025, 2047, 2048, 2049 }; - - public static void main(String[] args) throws Exception { - testFileChannel(); - for (int i=0; i theException = + new AtomicReference<>(); + AtomicBoolean isTimedOut = new AtomicBoolean(); Selector selector = Selector.open(); Thread t = new Thread(() -> { try { - isTimedOut = false; selector.select(timeout); - isTimedOut = true; + isTimedOut.set(true); } catch (IOException ioe) { - theException = ioe; + theException.set(ioe); } }); t.start(); @@ -77,8 +77,8 @@ public class SelectTimeout { t.join(SLEEP_MILLIS); boolean result; - if (theException == null) { - if (timeout > SLEEP_MILLIS && isTimedOut) { + if (theException.get() == null) { + if (timeout > SLEEP_MILLIS && isTimedOut.get()) { System.err.printf("Test timed out early with timeout %d%n", timeout); result = false; @@ -88,11 +88,12 @@ public class SelectTimeout { } } else { System.err.printf("Test failed with timeout %d%n", timeout); - theException.printStackTrace(); + theException.get().printStackTrace(); result = false; } t.interrupt(); + selector.close(); return result; } diff --git a/jdk/test/java/nio/file/FileSystem/Basic.java b/jdk/test/java/nio/file/FileSystem/Basic.java index 4b02ff498e7..4e780aff2d3 100644 --- a/jdk/test/java/nio/file/FileSystem/Basic.java +++ b/jdk/test/java/nio/file/FileSystem/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. * 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,11 +30,18 @@ */ import java.io.File; -import java.nio.file.*; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.ProviderNotFoundException; import java.util.HashMap; +import java.util.concurrent.TimeUnit; import jdk.testlibrary.FileUtils; /** @@ -47,6 +54,44 @@ public class Basic { throw new RuntimeException(msg); } + static void checkFileStores(String os, FileSystem fs) throws IOException { + boolean checkFileStores = true; + if (!os.equals("Windows")) { + // try to check whether 'df' hangs + System.out.println("\n--- Begin df output ---"); + System.out.flush(); + Process proc = new ProcessBuilder("df").inheritIO().start(); + try { + proc.waitFor(90, TimeUnit.SECONDS); + } catch (InterruptedException ignored) { + } + System.out.println("--- End df output ---\n"); + System.out.flush(); + try { + int exitValue = proc.exitValue(); + if (exitValue != 0) { + System.err.printf("df process exited with %d != 0%n", + exitValue); + checkFileStores = false; + } + } catch (IllegalThreadStateException ignored) { + System.err.println("df command apparently hung"); + checkFileStores = false; + } + } + + // sanity check method + if (checkFileStores) { + System.out.println("\n--- Begin FileStores ---"); + for (FileStore store: fs.getFileStores()) { + System.out.println(store); + } + System.out.println("--- EndFileStores ---\n"); + } else { + System.err.println("Skipping FileStore check due to df failure"); + } + } + static void checkSupported(FileSystem fs, String... views) { for (String view: views) { check(fs.supportedFileAttributeViews().contains(view), @@ -70,7 +115,9 @@ public class Basic { } } - public static void main(String[] args) throws IOException, URISyntaxException { + public static void main(String[] args) + throws IOException, URISyntaxException { + String os = System.getProperty("os.name"); FileSystem fs = FileSystems.getDefault(); // close should throw UOE @@ -85,15 +132,11 @@ public class Basic { check(fs.provider().getScheme().equals("file"), "should use 'file' scheme"); - // santity check method - need to re-visit this in future as I/O errors - // are possible - for (FileStore store: fs.getFileStores()) { - System.out.println(store); - } + // sanity check FileStores + checkFileStores(os, fs); // sanity check supportedFileAttributeViews checkSupported(fs, "basic"); - String os = System.getProperty("os.name"); if (os.equals("SunOS")) checkSupported(fs, "posix", "unix", "owner", "acl", "user"); if (os.equals("Linux")) diff --git a/jdk/test/java/security/modules/ModularTest.java b/jdk/test/java/security/modules/ModularTest.java index 9e67094944f..56635c99b8d 100644 --- a/jdk/test/java/security/modules/ModularTest.java +++ b/jdk/test/java/security/modules/ModularTest.java @@ -164,9 +164,9 @@ public abstract class ModularTest { final Builder builder; if (moduleType == MODULE_TYPE.EXPLICIT) { System.out.format(" %nGenerating ModuleDescriptor object"); - builder = ModuleDescriptor.module(moduleName).exports(pkg); + builder = ModuleDescriptor.newModule(moduleName).exports(pkg); if (isService && serviceInterface != null && serviceImpl != null) { - builder.provides(serviceInterface, serviceImpl); + builder.provides(serviceInterface, List.of(serviceImpl)); } else { if (serviceInterface != null) { builder.uses(serviceInterface); diff --git a/jdk/test/java/time/TEST.properties b/jdk/test/java/time/TEST.properties index f522b84681a..346e3e22580 100644 --- a/jdk/test/java/time/TEST.properties +++ b/jdk/test/java/time/TEST.properties @@ -1,6 +1,5 @@ -# Threeten test uses TestNG +# java.time tests use TestNG TestNG.dirs = . othervm.dirs = tck/java/time/chrono test/java/time/chrono test/java/time/format lib.dirs = ../../lib/testlibrary lib.build = jdk.testlibrary.RandomFactory -modules = java.base/java.time:open java.base/java.time.chrono:open java.base/java.time.zone:open diff --git a/jdk/test/java/time/tck/java/time/AbstractTCKTest.java b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java index d96011469a5..6272ea723cb 100644 --- a/jdk/test/java/time/tck/java/time/AbstractTCKTest.java +++ b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,14 +69,35 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamConstants; import java.io.Serializable; -import java.lang.reflect.Field; import java.util.Formatter; +import java.util.Map; /** * Base test class. */ public abstract class AbstractTCKTest { + /** + * Map from package name to the serialVersionUID of the .Ser class for the package. + */ + private static Map serialVersionUIDs = Map.of( + "java.time", -7683839454370182990L, + "java.time.chrono", -6103370247208168577L, + "java.time.zone", -8885321777449118786L + ); + + /** + * Returns the serialVersionUID for the class. + * The SUIDs are defined by the specification for each class. + * @param serClass the class to return the SUID of + * @return returns the serialVersionUID for the class + */ + public final static long getSUID(Class serClass) { + String pkgName = serClass.getPackageName(); + return serialVersionUIDs.get(pkgName); + } + + protected static boolean isIsoLeap(long year) { if (year % 4 != 0) { return false; @@ -111,10 +132,8 @@ public abstract class AbstractTCKTest { protected static void assertSerializedBySer(Object object, byte[] expectedBytes, byte[]... matches) throws Exception { String serClass = object.getClass().getPackage().getName() + ".Ser"; - Class serCls = Class.forName(serClass); - Field field = serCls.getDeclaredField("serialVersionUID"); - field.setAccessible(true); - long serVer = (Long) field.get(null); + long serVer = getSUID(object.getClass()); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) { oos.writeObject(object); @@ -172,9 +191,8 @@ public abstract class AbstractTCKTest { * @throws Exception if an unexpected condition occurs */ protected static void assertNotSerializable(Class serClass) throws Exception { - Field field = serClass.getDeclaredField("serialVersionUID"); - field.setAccessible(true); - long serVer = (Long) field.get(null); + long serVer = getSUID(serClass); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream out = new DataOutputStream(baos)) { out.writeShort(ObjectStreamConstants.STREAM_MAGIC); @@ -201,7 +219,6 @@ public abstract class AbstractTCKTest { fail("Class should not be deserializable " + serClass.getName()); } - /** * Utility method to dump a byte array in a java syntax. * @param bytes and array of bytes diff --git a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java index 991b447a506..1234083e297 100644 --- a/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,8 +104,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.time.Clock; import java.time.DateTimeException; import java.time.Duration; @@ -470,24 +468,12 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(expectedExceptions=NullPointerException.class) public void constructor_nullTime() throws Throwable { - Constructor con = OffsetDateTime.class.getDeclaredConstructor(LocalDateTime.class, ZoneOffset.class); - con.setAccessible(true); - try { - con.newInstance(null, OFFSET_PONE); - } catch (InvocationTargetException ex) { - throw ex.getCause(); - } + OffsetDateTime.of(null, OFFSET_PONE); } @Test(expectedExceptions=NullPointerException.class) public void constructor_nullOffset() throws Throwable { - Constructor con = OffsetDateTime.class.getDeclaredConstructor(LocalDateTime.class, ZoneOffset.class); - con.setAccessible(true); - try { - con.newInstance(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30)), null); - } catch (InvocationTargetException ex) { - throw ex.getCause(); - } + OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30)), null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java index 016cfc3e9d8..738bb86c2f4 100644 --- a/jdk/test/java/time/tck/java/time/TCKOffsetTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,8 +89,6 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.time.Clock; import java.time.DateTimeException; import java.time.Instant; @@ -465,28 +463,16 @@ public class TCKOffsetTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // constructor + // constructor via factory //----------------------------------------------------------------------- @Test(expectedExceptions=NullPointerException.class) public void constructor_nullTime() throws Throwable { - Constructor con = OffsetTime.class.getDeclaredConstructor(LocalTime.class, ZoneOffset.class); - con.setAccessible(true); - try { - con.newInstance(null, OFFSET_PONE); - } catch (InvocationTargetException ex) { - throw ex.getCause(); - } + OffsetTime.of(null, OFFSET_PONE); } @Test(expectedExceptions=NullPointerException.class) public void constructor_nullOffset() throws Throwable { - Constructor con = OffsetTime.class.getDeclaredConstructor(LocalTime.class, ZoneOffset.class); - con.setAccessible(true); - try { - con.newInstance(LocalTime.of(11, 30, 0, 0), null); - } catch (InvocationTargetException ex) { - throw ex.getCause(); - } + OffsetTime.of(LocalTime.of(11, 30, 0, 0), null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/serial/TCKZoneIdSerialization.java b/jdk/test/java/time/tck/java/time/serial/TCKZoneIdSerialization.java index c6f3abee38c..34c79c396e1 100644 --- a/jdk/test/java/time/tck/java/time/serial/TCKZoneIdSerialization.java +++ b/jdk/test/java/time/tck/java/time/serial/TCKZoneIdSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,8 +63,11 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import tck.java.time.AbstractTCKTest; -import java.io.*; -import java.lang.reflect.Field; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamConstants; import java.time.DateTimeException; import java.time.ZoneId; import java.time.zone.ZoneRulesException; @@ -153,10 +156,8 @@ public class TCKZoneIdSerialization extends AbstractTCKTest { private ZoneId deserialize(String id) throws Exception { String serClass = ZoneId.class.getPackage().getName() + ".Ser"; - Class serCls = Class.forName(serClass); - Field field = serCls.getDeclaredField("serialVersionUID"); - field.setAccessible(true); - long serVer = (Long) field.get(null); + long serVer = getSUID(ZoneId.class); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos)) { dos.writeShort(ObjectStreamConstants.STREAM_MAGIC); diff --git a/jdk/test/java/time/test/java/time/TEST.properties b/jdk/test/java/time/test/java/time/TEST.properties new file mode 100644 index 00000000000..75b4dd4403f --- /dev/null +++ b/jdk/test/java/time/test/java/time/TEST.properties @@ -0,0 +1,2 @@ +# java.time test system clock +modules = java.base/java.time:open diff --git a/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java index c28e3b91911..8d3c2d27d3a 100644 --- a/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java +++ b/jdk/test/java/util/ServiceLoader/modules/BadProvidersTest.java @@ -90,7 +90,7 @@ public class BadProvidersTest { Layer bootLayer = Layer.boot(); Configuration cf = bootLayer.configuration() - .resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of(moduleName)); + .resolveAndBind(finder, ModuleFinder.of(), Set.of(moduleName)); ClassLoader scl = ClassLoader.getSystemClassLoader(); diff --git a/jdk/test/java/util/ServiceLoader/modules/Basic.java b/jdk/test/java/util/ServiceLoader/modules/Basic.java index 7833c0e2771..4dca546ea36 100644 --- a/jdk/test/java/util/ServiceLoader/modules/Basic.java +++ b/jdk/test/java/util/ServiceLoader/modules/Basic.java @@ -311,17 +311,17 @@ public class Basic { ModuleFinder finder = ModuleFinder.of(dir); // layer1 - Configuration cf1 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of()); + Configuration cf1 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of()); Layer layer1 = bootLayer.defineModulesWithOneLoader(cf1, scl); assertTrue(layer1.modules().size() == 1); // layer2 - Configuration cf2 = cf0.resolveRequiresAndUses(finder, ModuleFinder.of(), Set.of()); + Configuration cf2 = cf0.resolveAndBind(finder, ModuleFinder.of(), Set.of()); Layer layer2 = bootLayer.defineModulesWithOneLoader(cf2, scl); assertTrue(layer2.modules().size() == 1); // layer3 with layer1 and layer2 as parents - Configuration cf3 = Configuration.resolveRequiresAndUses(finder, + Configuration cf3 = Configuration.resolveAndBind(finder, List.of(cf1, cf2), ModuleFinder.of(), Set.of()); @@ -413,7 +413,7 @@ public class Basic { Collections.addAll(roots, modules); Layer bootLayer = Layer.boot(); Configuration parent = bootLayer.configuration(); - Configuration cf = parent.resolveRequires(finder, ModuleFinder.of(), roots); + Configuration cf = parent.resolve(finder, ModuleFinder.of(), roots); ClassLoader scl = ClassLoader.getSystemClassLoader(); Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); assertTrue(layer.modules().size() == 1); diff --git a/jdk/test/java/util/concurrent/tck/ForkJoinPool9Test.java b/jdk/test/java/util/concurrent/tck/ForkJoinPool9Test.java new file mode 100644 index 00000000000..08cdfeb86dc --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/ForkJoinPool9Test.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea and Martin Buchholz with assistance from + * members of JCP JSR-166 Expert Group and released to the public + * domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.concurrent.CompletableFuture; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class ForkJoinPool9Test extends JSR166TestCase { + public static void main(String[] args) { + main(suite(), args); + } + + public static Test suite() { + return new TestSuite(ForkJoinPool9Test.class); + } + + /** + * Check handling of common pool thread context class loader + */ + public void testCommonPoolThreadContextClassLoader() throws Throwable { + if (!testImplementationDetails) return; + VarHandle CCL = + MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup()) + .findVarHandle(Thread.class, "contextClassLoader", ClassLoader.class); + ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); + boolean haveSecurityManager = (System.getSecurityManager() != null); + CompletableFuture.runAsync( + () -> { + assertSame(systemClassLoader, + Thread.currentThread().getContextClassLoader()); + assertSame(systemClassLoader, + CCL.get(Thread.currentThread())); + if (haveSecurityManager) + assertThrows( + SecurityException.class, + () -> System.getProperty("foo"), + () -> Thread.currentThread().setContextClassLoader(null)); + + // TODO ? +// if (haveSecurityManager +// && Thread.currentThread().getClass().getSimpleName() +// .equals("InnocuousForkJoinWorkerThread")) +// assertThrows(SecurityException.class, /* ?? */); + }).join(); + } + +} diff --git a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java index ff686081cd2..80eb346db4e 100644 --- a/jdk/test/java/util/concurrent/tck/JSR166TestCase.java +++ b/jdk/test/java/util/concurrent/tck/JSR166TestCase.java @@ -46,6 +46,7 @@ * @summary JSR-166 tck tests (whitebox tests allowed) * @build * * @modules java.base/java.util.concurrent:open + * java.base/java.lang:open * java.management * @run junit/othervm/timeout=1000 * -Djsr166.testImplementationDetails=true @@ -59,6 +60,9 @@ * -Djava.util.concurrent.ForkJoinPool.common.parallelism=1 * -Djava.util.secureRandomSeed=true * JSR166TestCase + * @run junit/othervm/timeout=1000/policy=tck.policy + * -Djsr166.testImplementationDetails=true + * JSR166TestCase */ import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -584,6 +588,7 @@ public class JSR166TestCase extends TestCase { "AtomicReference9Test", "AtomicReferenceArray9Test", "ExecutorCompletionService9Test", + "ForkJoinPool9Test", }; addNamedTestClasses(suite, java9TestClassNames); } @@ -594,7 +599,7 @@ public class JSR166TestCase extends TestCase { /** Returns list of junit-style test method names in given class. */ public static ArrayList testMethodNames(Class testClass) { Method[] methods = testClass.getDeclaredMethods(); - ArrayList names = new ArrayList(methods.length); + ArrayList names = new ArrayList<>(methods.length); for (Method method : methods) { if (method.getName().startsWith("test") && Modifier.isPublic(method.getModifiers()) @@ -700,7 +705,7 @@ public class JSR166TestCase extends TestCase { * The first exception encountered if any threadAssertXXX method fails. */ private final AtomicReference threadFailure - = new AtomicReference(null); + = new AtomicReference<>(null); /** * Records an exception so that it can be rethrown later in the test @@ -1262,7 +1267,7 @@ public class JSR166TestCase extends TestCase { } public void refresh() {} public String toString() { - List ps = new ArrayList(); + List ps = new ArrayList<>(); for (Enumeration e = perms.elements(); e.hasMoreElements();) ps.add(e.nextElement()); return "AdjustablePolicy with permissions " + ps; diff --git a/jdk/test/java/util/concurrent/tck/tck.policy b/jdk/test/java/util/concurrent/tck/tck.policy new file mode 100644 index 00000000000..5816ab31c50 --- /dev/null +++ b/jdk/test/java/util/concurrent/tck/tck.policy @@ -0,0 +1,15 @@ +grant { + // Permissions j.u.c. needs directly + permission java.lang.RuntimePermission "modifyThread"; + permission java.lang.RuntimePermission "getClassLoader"; + permission java.lang.RuntimePermission "setContextClassLoader"; + permission java.util.PropertyPermission "*", "read"; + // Permissions needed to change permissions! + permission java.security.SecurityPermission "getPolicy"; + permission java.security.SecurityPermission "setPolicy"; + permission java.security.SecurityPermission "setSecurityManager"; + // Permissions needed by the junit test harness + permission java.lang.RuntimePermission "accessDeclaredMembers"; + permission java.io.FilePermission "<>", "read"; + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; +}; diff --git a/jdk/test/jdk/internal/reflect/CallerSensitive/CheckCSMs.java b/jdk/test/jdk/internal/reflect/CallerSensitive/CheckCSMs.java new file mode 100644 index 00000000000..126df3a75e6 --- /dev/null +++ b/jdk/test/jdk/internal/reflect/CallerSensitive/CheckCSMs.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 com.sun.tools.classfile.*; +import com.sun.tools.jdeps.ClassFileReader; +import static com.sun.tools.classfile.ConstantPool.*; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/* + * @test + * @summary CallerSensitive methods should be static or final instance + * methods except the known list of non-final instance methods + * @modules jdk.jdeps/com.sun.tools.classfile + * jdk.jdeps/com.sun.tools.jdeps + * @build CheckCSMs + * @run main/othervm/timeout=900 CheckCSMs + */ +public class CheckCSMs { + private static int numThreads = 3; + private static boolean listCSMs = false; + private final ExecutorService pool; + + // The goal is to remove this list of Non-final instance @CS methods + // over time. Do not add any new one to this list. + private static Set KNOWN_NON_FINAL_CSMS = + Set.of("java/io/ObjectStreamField#getType ()Ljava/lang/Class;", + "java/io/ObjectStreamClass#forClass ()Ljava/lang/Class;", + "java/lang/Runtime#load (Ljava/lang/String;)V", + "java/lang/Runtime#loadLibrary (Ljava/lang/String;)V", + "java/lang/Thread#getContextClassLoader ()Ljava/lang/ClassLoader;", + "javax/sql/rowset/serial/SerialJavaObject#getFields ()[Ljava/lang/reflect/Field;" + ); + + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("--list")) { + listCSMs = true; + } + + CheckCSMs checkCSMs = new CheckCSMs(); + Set result = checkCSMs.run(getPlatformClasses()); + if (!KNOWN_NON_FINAL_CSMS.equals(result)) { + Set diff = new HashSet<>(result); + diff.removeAll(KNOWN_NON_FINAL_CSMS); + throw new RuntimeException("Unexpected non-final instance method: " + + result.stream().sorted() + .collect(Collectors.joining("\n", "\n", ""))); + } + } + + private final Set nonFinalCSMs = new ConcurrentSkipListSet<>(); + private final ReferenceFinder finder; + public CheckCSMs() { + this.finder = new ReferenceFinder(getFilter(), getVisitor()); + pool = Executors.newFixedThreadPool(numThreads); + + } + + public Set run(Stream classes) + throws IOException, InterruptedException, ExecutionException, + ConstantPoolException + { + classes.forEach(this::processPath); + waitForCompletion(); + pool.shutdown(); + return nonFinalCSMs; + } + + + private ReferenceFinder.Filter getFilter() { + final String classname = "jdk/internal/reflect/Reflection"; + final String method = "getCallerClass"; + return new ReferenceFinder.Filter() { + public boolean accept(ConstantPool cpool, CPRefInfo cpref) { + try { + CONSTANT_NameAndType_info nat = cpref.getNameAndTypeInfo(); + return cpref.getClassName().equals(classname) && nat.getName().equals(method); + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + }; + } + + private ReferenceFinder.Visitor getVisitor() { + return new ReferenceFinder.Visitor() { + public void visit(ClassFile cf, Method m, List refs) { + try { + // ignore jdk.unsupported/sun.reflect.Reflection.getCallerClass + // which is a "special" delegate to the internal getCallerClass + if (cf.getName().equals("sun/reflect/Reflection") && + m.getName(cf.constant_pool).equals("getCallerClass")) + return; + + String name = String.format("%s#%s %s", cf.getName(), + m.getName(cf.constant_pool), + m.descriptor.getValue(cf.constant_pool)); + if (!CheckCSMs.isStaticOrFinal(cf, m, cf.constant_pool)) { + System.err.println("Unsupported @CallerSensitive: " + name); + nonFinalCSMs.add(name); + } else { + if (listCSMs) { + System.out.format("@CS %s%n", name); + } + } + } catch (ConstantPoolException ex) { + throw new RuntimeException(ex); + } + } + }; + } + + void processPath(Path path) { + try { + ClassFileReader reader = ClassFileReader.newInstance(path); + for (ClassFile cf : reader.getClassFiles()) { + if (cf.access_flags.is(AccessFlags.ACC_MODULE)) + continue; + + String classFileName = cf.getName(); + // for each ClassFile + // parse constant pool to find matching method refs + // parse each method (caller) + // - visit and find method references matching the given method name + pool.submit(getTask(cf)); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } catch (ConstantPoolException x) { + throw new RuntimeException(x); + } + } + + private static final String CALLER_SENSITIVE_ANNOTATION + = "Ljdk/internal/reflect/CallerSensitive;"; + + private static boolean isCallerSensitive(Method m, ConstantPool cp) + throws ConstantPoolException + { + RuntimeAnnotations_attribute attr = + (RuntimeAnnotations_attribute)m.attributes.get(Attribute.RuntimeVisibleAnnotations); + if (attr != null) { + for (int i = 0; i < attr.annotations.length; i++) { + Annotation ann = attr.annotations[i]; + String annType = cp.getUTF8Value(ann.type_index); + if (CALLER_SENSITIVE_ANNOTATION.equals(annType)) { + return true; + } + } + } + return false; + } + + private static boolean isStaticOrFinal(ClassFile cf, Method m, ConstantPool cp) + throws ConstantPoolException + { + if (!isCallerSensitive(m, cp)) + return false; + + // either a static method or a final instance method + return m.access_flags.is(AccessFlags.ACC_STATIC) || + m.access_flags.is(AccessFlags.ACC_FINAL) || + cf.access_flags.is(AccessFlags.ACC_FINAL); + } + + private final List> tasks = new ArrayList>(); + private FutureTask getTask(final ClassFile cf) { + FutureTask task = new FutureTask(new Callable() { + public Void call() throws Exception { + finder.parse(cf); + return null; + } + }); + tasks.add(task); + return task; + } + + private void waitForCompletion() throws InterruptedException, ExecutionException { + for (FutureTask t : tasks) { + t.get(); + } + if (tasks.isEmpty()) { + throw new RuntimeException("No classes found, or specified."); + } + System.out.println("Parsed " + tasks.size() + " classfiles"); + } + + static Stream getPlatformClasses() throws IOException { + Path home = Paths.get(System.getProperty("java.home")); + + // Either an exploded build or an image. + File classes = home.resolve("modules").toFile(); + if (classes.isDirectory()) { + return Stream.of(classes.toPath()); + } else { + return jrtPaths(); + } + } + + static Stream jrtPaths() { + FileSystem jrt = FileSystems.getFileSystem(URI.create("jrt:/")); + Path root = jrt.getPath("/"); + + try { + return Files.walk(root) + .filter(p -> p.getNameCount() > 1) + .filter(p -> p.toString().endsWith(".class")); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } +} diff --git a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java index 72e337066cb..182fb4ee985 100644 --- a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java +++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java @@ -46,7 +46,7 @@ public class VerifyModuleDelegation { private static final String JAVA_BASE = "java.base"; private static final ModuleDescriptor BASE - = ModuleDescriptor.module(JAVA_BASE).build(); + = ModuleDescriptor.newModule(JAVA_BASE).build(); private static final Set MREFS = Layer.boot().modules().stream().map(Module::getDescriptor) diff --git a/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java b/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java index 67f2416187f..ca3f0f3a0d2 100644 --- a/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java +++ b/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java @@ -71,9 +71,9 @@ public class Main { ModuleFinder finder = ModuleFinder.of(paths); Configuration cf = Layer.boot().configuration() - .resolveRequiresAndUses(finder, - ModuleFinder.of(), - Set.of(appModuleName)); + .resolveAndBind(finder, + ModuleFinder.of(), + Set.of(appModuleName)); System.out.println("Resolved"); cf.modules().stream() diff --git a/jdk/test/org/omg/CORBA/OrbPropertiesTest.java b/jdk/test/org/omg/CORBA/OrbPropertiesTest.java new file mode 100644 index 00000000000..977b2e9b110 --- /dev/null +++ b/jdk/test/org/omg/CORBA/OrbPropertiesTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +import org.omg.CORBA.ORB; + +/* + * @test + * @bug 8049375 + * @summary Extend how the org.omg.CORBA.ORB handles the search for orb.properties + * @library /lib/testlibrary + * @build jdk.testlibrary.* + * @modules java.corba + * @compile OrbPropertiesTest.java TestOrbImpl.java TestSingletonOrbImpl.java + * @run main/othervm + * -Djava.naming.provider.url=iiop://localhost:1050 + * -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory + * OrbPropertiesTest -port 1049 + * @run main/othervm/secure=java.lang.SecurityManager/policy=jtreg.test.policy + * -Djava.naming.provider.url=iiop://localhost:3050 + * -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory + * OrbPropertiesTest -port 3049 + */ +public class OrbPropertiesTest { + + public static void main(String[] args) throws Exception { + updateOrbPropertiesFile(); + // create and initialize the ORB + ORB orb = ORB.init(args, null); + if (!(orb instanceof TestOrbImpl)) { + throw new RuntimeException("org.omg.CORBA.ORBClass property not set as expected"); + } + ORB singletonOrb = ORB.init(); + System.out.println("singletonOrb class == " + singletonOrb.getClass().getName()); + if (!(singletonOrb instanceof TestSingletonOrbImpl)) { + throw new RuntimeException("org.omg.CORBA.ORBSingletonClass property not set as expected"); + } + + } + + private static void updateOrbPropertiesFile() throws Exception { + String orbPropertiesFile = System.getProperty("java.home", ".") + "/conf/orb.properties"; + String orbClassMapping = "org.omg.CORBA.ORBClass TestOrbImpl"; + String orbSingletonClassMapping = "org.omg.CORBA.ORBSingletonClass TestSingletonOrbImpl"; + String orbPropertiesMappings = orbClassMapping + "\n" + orbSingletonClassMapping +"\n"; + try (PrintWriter hfPWriter = new PrintWriter(new BufferedWriter( + new FileWriter(orbPropertiesFile, false)))) { + hfPWriter.println(orbPropertiesMappings); + } catch (IOException ioEx) { + ioEx.printStackTrace(); + throw ioEx; + } + } +} diff --git a/jdk/test/org/omg/CORBA/TestOrbImpl.java b/jdk/test/org/omg/CORBA/TestOrbImpl.java new file mode 100644 index 00000000000..1dd7d661b3a --- /dev/null +++ b/jdk/test/org/omg/CORBA/TestOrbImpl.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.applet.Applet; +import java.util.Properties; + +import org.omg.CORBA.Any; +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.Environment; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.Request; +import org.omg.CORBA.StructMember; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UnionMember; +import org.omg.CORBA.WrongTransaction; +import org.omg.CORBA.ORBPackage.InvalidName; +import org.omg.CORBA.portable.OutputStream; + + +public class TestOrbImpl extends ORB{ + + @Override + protected void set_parameters(String[] args, Properties props) { + + } + + @Override + protected void set_parameters(Applet app, Properties props) { + + } + + @Override + public String[] list_initial_services() { + return null; + } + + @Override + public Object resolve_initial_references(String object_name) + throws InvalidName { + return null; + } + + @Override + public String object_to_string(Object obj) { + return null; + } + + @Override + public Object string_to_object(String str) { + return null; + } + + @Override + public NVList create_list(int count) { + return null; + } + + @Override + public NamedValue create_named_value(String s, Any any, int flags) { + return null; + } + + @Override + public ExceptionList create_exception_list() { + return null; + } + + @Override + public ContextList create_context_list() { + return null; + } + + @Override + public Context get_default_context() { + return null; + } + + @Override + public Environment create_environment() { + return null; + } + + @Override + public OutputStream create_output_stream() { + return null; + } + + @Override + public void send_multiple_requests_oneway(Request[] req) { + + } + + @Override + public void send_multiple_requests_deferred(Request[] req) { + + } + + @Override + public boolean poll_next_response() { + return false; + } + + @Override + public Request get_next_response() throws WrongTransaction { + return null; + } + + @Override + public TypeCode get_primitive_tc(TCKind tcKind) { + return null; + } + + @Override + public TypeCode create_struct_tc(String id, String name, + StructMember[] members) { + return null; + } + + @Override + public TypeCode create_union_tc(String id, String name, + TypeCode discriminator_type, UnionMember[] members) { + return null; + } + + @Override + public TypeCode create_enum_tc(String id, String name, String[] members) { + return null; + } + + @Override + public TypeCode create_alias_tc(String id, String name, + TypeCode original_type) { + return null; + } + + @Override + public TypeCode create_exception_tc(String id, String name, + StructMember[] members) { + return null; + } + + @Override + public TypeCode create_interface_tc(String id, String name) { + return null; + } + + @Override + public TypeCode create_string_tc(int bound) { + return null; + } + + @Override + public TypeCode create_wstring_tc(int bound) { + return null; + } + + @Override + public TypeCode create_sequence_tc(int bound, TypeCode element_type) { + return null; + } + + @Override + public TypeCode create_recursive_sequence_tc(int bound, int offset) { + return null; + } + + @Override + public TypeCode create_array_tc(int length, TypeCode element_type) { + return null; + } + + @Override + public Any create_any() { + return null; + } + +} diff --git a/jdk/test/org/omg/CORBA/TestSingletonOrbImpl.java b/jdk/test/org/omg/CORBA/TestSingletonOrbImpl.java new file mode 100644 index 00000000000..fb6a26f807a --- /dev/null +++ b/jdk/test/org/omg/CORBA/TestSingletonOrbImpl.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.applet.Applet; +import java.util.Properties; + +import org.omg.CORBA.Any; +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.Environment; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.Request; +import org.omg.CORBA.StructMember; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UnionMember; +import org.omg.CORBA.WrongTransaction; +import org.omg.CORBA.ORBPackage.InvalidName; +import org.omg.CORBA.portable.OutputStream; + + +public class TestSingletonOrbImpl extends ORB { + + @Override + protected void set_parameters(String[] args, Properties props) { + + } + + @Override + protected void set_parameters(Applet app, Properties props) { + + } + + @Override + public String[] list_initial_services() { + return null; + } + + @Override + public Object resolve_initial_references(String object_name) + throws InvalidName { + return null; + } + + @Override + public String object_to_string(Object obj) { + return null; + } + + @Override + public Object string_to_object(String str) { + return null; + } + + @Override + public NVList create_list(int count) { + return null; + } + + @Override + public NamedValue create_named_value(String s, Any any, int flags) { + return null; + } + + @Override + public ExceptionList create_exception_list() { + return null; + } + + @Override + public ContextList create_context_list() { + return null; + } + + @Override + public Context get_default_context() { + return null; + } + + @Override + public Environment create_environment() { + return null; + } + + @Override + public OutputStream create_output_stream() { + return null; + } + + @Override + public void send_multiple_requests_oneway(Request[] req) { + + } + + @Override + public void send_multiple_requests_deferred(Request[] req) { + + } + + @Override + public boolean poll_next_response() { + return false; + } + + @Override + public Request get_next_response() throws WrongTransaction { + return null; + } + + @Override + public TypeCode get_primitive_tc(TCKind tcKind) { + return null; + } + + @Override + public TypeCode create_struct_tc(String id, String name, + StructMember[] members) { + return null; + } + + @Override + public TypeCode create_union_tc(String id, String name, + TypeCode discriminator_type, UnionMember[] members) { + return null; + } + + @Override + public TypeCode create_enum_tc(String id, String name, String[] members) { + return null; + } + + @Override + public TypeCode create_alias_tc(String id, String name, + TypeCode original_type) { + return null; + } + + @Override + public TypeCode create_exception_tc(String id, String name, + StructMember[] members) { + return null; + } + + @Override + public TypeCode create_interface_tc(String id, String name) { + return null; + } + + @Override + public TypeCode create_string_tc(int bound) { + return null; + } + + @Override + public TypeCode create_wstring_tc(int bound) { + return null; + } + + @Override + public TypeCode create_sequence_tc(int bound, TypeCode element_type) { + return null; + } + + @Override + public TypeCode create_recursive_sequence_tc(int bound, int offset) { + return null; + } + + @Override + public TypeCode create_array_tc(int length, TypeCode element_type) { + return null; + } + + @Override + public Any create_any() { + return null; + } + +} diff --git a/jdk/test/org/omg/CORBA/jtreg.test.policy b/jdk/test/org/omg/CORBA/jtreg.test.policy new file mode 100644 index 00000000000..0e24009f687 --- /dev/null +++ b/jdk/test/org/omg/CORBA/jtreg.test.policy @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +grant { + permission java.util.PropertyPermission "*", "read"; + permission java.io.FilePermission "<>", "read, write, execute"; +}; + +grant codeBase "file:${test.classes}/*" { + permission java.net.SocketPermission "*:*", "connect, accept, listen, resolve"; + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.jndi.cosnaming"; +}; diff --git a/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java b/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java index 9ee4a0cd820..4e628995c18 100644 --- a/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java +++ b/jdk/test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java @@ -27,7 +27,7 @@ * @summary Verify a non-zero value is assigned to jmxremote.port * when VM is started with jmxremote.port=0. * @library /lib/testlibrary - * @modules java.management/sun.management.jdp + * @modules jdk.management.agent/sun.management.jdp * @build jdk.testlibrary.* ClientConnection JdpTestUtil JdpTestCase JdpJmxRemoteDynamicPortTestCase DynamicLauncher * @run main JdpJmxRemoteDynamicPortTest */ diff --git a/jdk/test/sun/security/ssl/ServerHandshaker/HelloExtensionsTest.java b/jdk/test/sun/security/ssl/ServerHandshaker/HelloExtensionsTest.java new file mode 100644 index 00000000000..bb84d5f01f9 --- /dev/null +++ b/jdk/test/sun/security/ssl/ServerHandshaker/HelloExtensionsTest.java @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8173783 + * @summary 6u141 IllegalArgumentException: jdk.tls.namedGroups + * run main/othervm HelloExtensionsTest + * run main/othervm HelloExtensionsTest -Djdk.tls.namedGroups="bug, bug" + * run main/othervm HelloExtensionsTest -Djdk.tls.namedGroups="secp521r1" + * + */ +import javax.crypto.*; +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.*; +import java.io.*; +import java.nio.*; +import java.security.*; + +public class HelloExtensionsTest { + + private static boolean debug = false; + private static boolean proceed = true; + private static boolean EcAvailable = isEcAvailable(); + + static String pathToStores = "../../../../javax/net/ssl/etc"; + private static String keyStoreFile = "keystore"; + private static String trustStoreFile = "truststore"; + private static String passwd = "passphrase"; + + private static String keyFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + keyStoreFile; + private static String trustFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + trustStoreFile; + + private static void checkDone(SSLEngine ssle) throws Exception { + if (!ssle.isInboundDone()) { + throw new Exception("isInboundDone isn't done"); + } + if (!ssle.isOutboundDone()) { + throw new Exception("isOutboundDone isn't done"); + } + } + + private static void runTest(SSLEngine ssle) throws Exception { + + /* + + A client hello message captured via wireshark by selecting + a TLSv1.2 Client Hello record and clicking through to the + TLSv1.2 Record Layer line and then selecting the hex stream + via "copy -> bytes -> hex stream". + + For Record purposes, here's the ClientHello : + + *** ClientHello, TLSv1.2 + RandomCookie: GMT: 1469560450 bytes = { 108, 140, 12, 202, + 2, 213, 10, 236, 143, 223, 58, 162, 228, 155, 239, 3, 98, + 232, 89, 41, 116, 120, 13, 37, 105, 153, 97, 241 } + Session ID: {} + Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + SSL_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, + TLS_EMPTY_RENEGOTIATION_INFO_SCSV] + Compression Methods: { 0 } + Extension elliptic_curves, curve names: {secp256r1, + sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, + sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, + sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, + secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1} + Extension ec_point_formats, formats: [uncompressed] + Extension signature_algorithms, signature_algorithms: + SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, + SHA256withECDSA, SHA256withRSA, Unknown (hash:0x3, signature:0x3), + Unknown (hash:0x3, signature:0x1), SHA1withECDSA, + SHA1withRSA, SHA1withDSA + Extension server_name, server_name: + [host_name: bugs.openjdk.java.net] + */ + + String hello = "16030300df010000db03035898b7826c8c0cc" + + "a02d50aec8fdf3aa2e49bef0362e8592974780d25699961f" + + "100003ac023c027003cc025c02900670040c009c013002fc" + + "004c00e00330032c02bc02f009cc02dc031009e00a2c008c" + + "012000ac003c00d0016001300ff01000078000a003400320" + + "0170001000300130015000600070009000a0018000b000c0" + + "019000d000e000f001000110002001200040005001400080" + + "016000b00020100000d00180016060306010503050104030" + + "401030303010203020102020000001a00180000156275677" + + "32e6f70656e6a646b2e6a6176612e6e6574"; + + byte[] msg_clihello = hexStringToByteArray(hello); + ByteBuffer bf_clihello = ByteBuffer.wrap(msg_clihello); + + SSLSession session = ssle.getSession(); + int appBufferMax = session.getApplicationBufferSize(); + int netBufferMax = session.getPacketBufferSize(); + + ByteBuffer serverIn = ByteBuffer.allocate(appBufferMax + 50); + ByteBuffer serverOut = ByteBuffer.wrap("I'm Server".getBytes()); + ByteBuffer sTOc = ByteBuffer.allocate(netBufferMax); + + ssle.beginHandshake(); + + // unwrap the clientHello message. + SSLEngineResult result = ssle.unwrap(bf_clihello, serverIn); + System.out.println("server unwrap " + result); + runDelegatedTasks(result, ssle); + + if (!proceed) { + //expected exception occurred. Don't process anymore + return; + } + + // one more step, ensure the clientHello message is parsed. + SSLEngineResult.HandshakeStatus status = ssle.getHandshakeStatus(); + if ( status == HandshakeStatus.NEED_UNWRAP) { + result = ssle.unwrap(bf_clihello, serverIn); + System.out.println("server unwrap " + result); + runDelegatedTasks(result, ssle); + } else if ( status == HandshakeStatus.NEED_WRAP) { + result = ssle.wrap(serverOut, sTOc); + System.out.println("server wrap " + result); + runDelegatedTasks(result, ssle); + } else { + throw new Exception("unexpected handshake status " + status); + } + + // enough, stop + } + + /* + * If the result indicates that we have outstanding tasks to do, + * go ahead and run them in this thread. + */ + private static void runDelegatedTasks(SSLEngineResult result, + SSLEngine engine) throws Exception { + + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + try { + while ((runnable = engine.getDelegatedTask()) != null) { + log("\trunning delegated task..."); + runnable.run(); + } + } catch (ExceptionInInitializerError e) { + String v = System.getProperty("jdk.tls.namedGroups"); + if (!EcAvailable || v == null) { + // we weren't expecting this if no EC providers + throw new RuntimeException("Unexpected Error :" + e); + } + if (v != null && v.contains("bug")) { + // OK - we were expecting this Error + log("got expected error for bad jdk.tls.namedGroups"); + proceed = false; + return; + } else { + System.out.println("Unexpected error. " + + "jdk.tls.namedGroups value: " + v); + throw e; + } + } + HandshakeStatus hsStatus = engine.getHandshakeStatus(); + if (hsStatus == HandshakeStatus.NEED_TASK) { + throw new Exception( + "handshake shouldn't need additional tasks"); + } + log("\tnew HandshakeStatus: " + hsStatus); + } + } + + private static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + return data; + } + + private static boolean isEcAvailable() { + try { + Signature.getInstance("SHA1withECDSA"); + Signature.getInstance("NONEwithECDSA"); + KeyAgreement.getInstance("ECDH"); + KeyFactory.getInstance("EC"); + KeyPairGenerator.getInstance("EC"); + AlgorithmParameters.getInstance("EC"); + } catch (Exception e) { + log("EC not available. Received: " + e); + return false; + } + return true; + } + + public static void main(String args[]) throws Exception { + SSLEngine ssle = createSSLEngine(keyFilename, trustFilename); + runTest(ssle); + System.out.println("Test Passed."); + } + + /* + * Create an initialized SSLContext to use for this test. + */ + static private SSLEngine createSSLEngine(String keyFile, String trustFile) + throws Exception { + + SSLEngine ssle; + + KeyStore ks = KeyStore.getInstance("JKS"); + KeyStore ts = KeyStore.getInstance("JKS"); + + char[] passphrase = "passphrase".toCharArray(); + + ks.load(new FileInputStream(keyFile), passphrase); + ts.load(new FileInputStream(trustFile), passphrase); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(ts); + + SSLContext sslCtx = SSLContext.getInstance("TLS"); + + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + ssle = sslCtx.createSSLEngine(); + ssle.setUseClientMode(false); + + return ssle; + } + + + private static void log(String str) { + if (debug) { + System.out.println(str); + } + } +} diff --git a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java index 9ba18ac0f05..8cb2541f151 100644 --- a/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java +++ b/jdk/test/sun/security/tools/jarsigner/TimestampCheck.java @@ -456,7 +456,7 @@ public class TimestampCheck { .shouldMatch("Timestamp signature algorithm: .*key.*weak"); verify(file, "-J-Djava.security.debug=jar") .shouldHaveExitValue(0) - .shouldMatch("SignatureException:.*Disabled"); + .shouldMatch("SignatureException:.*disabled"); } static void checkHalfWeak(String file) throws Throwable { diff --git a/jdk/test/tools/jar/mmrjar/Basic.java b/jdk/test/tools/jar/mmrjar/Basic.java index 6b0ad843641..0e83508b74d 100644 --- a/jdk/test/tools/jar/mmrjar/Basic.java +++ b/jdk/test/tools/jar/mmrjar/Basic.java @@ -331,7 +331,7 @@ public class Basic { ModuleInfoExtender mie = ModuleInfoExtender.newExtender( new ByteArrayInputStream(mdBytes)); - mie.mainClass("foo.main"); + mie.mainClass("p.Main"); mie.version(Version.parse("1.0")); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -345,7 +345,7 @@ public class Basic { // different main-class mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes)); - mie.mainClass("foo.main2"); + mie.mainClass("p.Main2"); mie.version(Version.parse("1.0")); baos.reset(); mie.write(baos); @@ -360,7 +360,7 @@ public class Basic { // different version mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes)); - mie.mainClass("foo.main"); + mie.mainClass("p.Main"); mie.version(Version.parse("2.0")); baos.reset(); mie.write(baos); @@ -395,7 +395,7 @@ public class Basic { Files.copy(Paths.get("test7-v9", "module-info.class"), Paths.get("test7-v10", "module-info.class")); - int rc = jar("--create --file mmr.jar --main-class=foo.main -C test7 . --release 9 -C test7-v9 . --release 10 -C test7-v10 ."); + int rc = jar("--create --file mmr.jar --main-class=p.Main -C test7 . --release 9 -C test7-v9 . --release 10 -C test7-v10 ."); System.out.println("-----------------------"); System.out.println( new String(errbytes.toByteArray())); @@ -409,7 +409,7 @@ System.out.println( new String(errbytes.toByteArray())); System.out.println("-----------------------"); System.out.println( new String(outbytes.toByteArray())); - Optional exp = Optional.of("foo.main"); + Optional exp = Optional.of("p.Main"); try (ZipFile zf = new ZipFile("mmr.jar")) { Assert.assertTrue(zf.getEntry("module-info.class") == null); diff --git a/jdk/test/tools/jar/modularJar/Basic.java b/jdk/test/tools/jar/modularJar/Basic.java index 8a9d44132fc..497853b769e 100644 --- a/jdk/test/tools/jar/modularJar/Basic.java +++ b/jdk/test/tools/jar/modularJar/Basic.java @@ -328,7 +328,7 @@ public class Basic { .resultChecker(r -> assertModuleData(r, FOO)); } - @Test + @Test(enabled = false) public void partialUpdateFooMainClass() throws IOException { Path mp = Paths.get("partialUpdateFooMainClass"); createTestDir(mp); diff --git a/jdk/test/tools/jlink/JLinkNegativeTest.java b/jdk/test/tools/jlink/JLinkNegativeTest.java index f8ac8093f33..b97092e4bac 100644 --- a/jdk/test/tools/jlink/JLinkNegativeTest.java +++ b/jdk/test/tools/jlink/JLinkNegativeTest.java @@ -274,7 +274,7 @@ public class JLinkNegativeTest { helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName2, classNames); try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { - ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1) + ModuleInfoWriter.write(ModuleDescriptor.newModule(moduleName1) .requires("java.base").build(), out); } @@ -332,7 +332,7 @@ public class JLinkNegativeTest { helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName2, classNames); try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { - ModuleInfoWriter.write(ModuleDescriptor.module(moduleName1) + ModuleInfoWriter.write(ModuleDescriptor.newModule(moduleName1) .requires("java.base").build(), out); } diff --git a/jdk/test/tools/jmod/hashes/HashesTest.java b/jdk/test/tools/jmod/hashes/HashesTest.java index 3700554983f..10680927c19 100644 --- a/jdk/test/tools/jmod/hashes/HashesTest.java +++ b/jdk/test/tools/jmod/hashes/HashesTest.java @@ -312,9 +312,7 @@ public class HashesTest { assertTrue(ht.hashes("m2") == null); // should not override any JDK packaged modules - ModuleFinder finder = new ModulePath(Runtime.version(), - true, - mpath); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, mpath); assertTrue(ht.hashes(finder,"jdk.compiler") == null); assertTrue(ht.hashes(finder,"jdk.attach") == null); } @@ -325,9 +323,7 @@ public class HashesTest { } private ModuleHashes hashes(String name) { - ModuleFinder finder = new ModulePath(Runtime.version(), - true, - lib); + ModuleFinder finder = ModulePath.of(Runtime.version(), true, lib); return hashes(finder, name); } diff --git a/jdk/test/tools/launcher/ArgsEnvVar.java b/jdk/test/tools/launcher/ArgsEnvVar.java index 30644e19a70..fe18e1d256c 100644 --- a/jdk/test/tools/launcher/ArgsEnvVar.java +++ b/jdk/test/tools/launcher/ArgsEnvVar.java @@ -40,7 +40,7 @@ public class ArgsEnvVar extends TestHelper { private static File testJar = null; private static Map env = new HashMap<>(); - private static String JAVA_OPTIONS = "JAVA_OPTIONS"; + private static String JDK_JAVA_OPTIONS = "JDK_JAVA_OPTIONS"; static void init() throws IOException { if (testJar != null) { @@ -105,7 +105,7 @@ public class ArgsEnvVar extends TestHelper { File argFile2 = createArgFile("argFile2", List.of("-Darg.file2=TWO")); File argFile3 = createArgFile("argFile3", List.of("-Darg.file3=THREE")); - env.put(JAVA_OPTIONS, "@argFile1\n-Xint\r-cp @@escaped\t@argFile2"); + env.put(JDK_JAVA_OPTIONS, "@argFile1\n-Xint\r-cp @@escaped\t@argFile2"); TestResult tr = doExec(env, javaCmd, "@argFile3", "-cp", "test.jar", "Foo", "uarg1", "@uarg2"); @@ -133,13 +133,13 @@ public class ArgsEnvVar extends TestHelper { } private TestResult testInEnv(List options) { - env.put(JAVA_OPTIONS, String.join(" ", options)); + env.put(JDK_JAVA_OPTIONS, String.join(" ", options)); return doExec(env, javaCmd, "-jar", "test.jar"); } private TestResult testInEnvAsArgFile(List options) throws IOException { File argFile = createArgFile("argFile", options); - env.put(JAVA_OPTIONS, "@argFile"); + env.put(JDK_JAVA_OPTIONS, "@argFile"); TestResult tr = doExec(env, javaCmd, "-jar", "test.jar"); argFile.delete(); return tr; @@ -187,7 +187,7 @@ public class ArgsEnvVar extends TestHelper { File argFile1 = createArgFile("arg File 1", List.of("-Xint")); File argFile2 = createArgFile("arg File 2", List.of("-Dprop='value with spaces'")); File argFile3 = createArgFile("arg File 3", List.of("-Xmx32m")); - env.put(JAVA_OPTIONS, "'@arg File 1' @\"arg File 2\" @'arg File'\" 3\""); + env.put(JDK_JAVA_OPTIONS, "'@arg File 1' @\"arg File 2\" @'arg File'\" 3\""); TestResult tr = doExec(env, javaCmd, "-jar", "test.jar"); List options = new ArrayList<>(); @@ -204,7 +204,7 @@ public class ArgsEnvVar extends TestHelper { @Test public void openQuoteShouldFail() { - env.put(JAVA_OPTIONS, "-Dprop='value missing close quote"); + env.put(JDK_JAVA_OPTIONS, "-Dprop='value missing close quote"); TestResult tr = doExec(env, javaCmd, "-version"); tr.checkNegative(); if (!tr.testStatus) { @@ -215,11 +215,11 @@ public class ArgsEnvVar extends TestHelper { @Test public void noWildcard() { - env.put(JAVA_OPTIONS, "-cp *"); + env.put(JDK_JAVA_OPTIONS, "-cp *"); TestResult tr = doExec(env, javaCmd, "-jar", "test.jar"); verifyOptions(List.of("-cp", "*", "-jar", "test.jar"), tr); - env.put(JAVA_OPTIONS, "-p ?"); + env.put(JDK_JAVA_OPTIONS, "-p ?"); tr = doExec(env, javaCmd, "-jar", "test.jar", "one", "two"); verifyOptions(List.of("-p", "?", "-jar", "test.jar", "one", "two"), tr); } diff --git a/jdk/test/tools/launcher/I18NArgTest.java b/jdk/test/tools/launcher/I18NArgTest.java index 25f4ec113ba..fa09736da2f 100644 --- a/jdk/test/tools/launcher/I18NArgTest.java +++ b/jdk/test/tools/launcher/I18NArgTest.java @@ -95,21 +95,19 @@ public class I18NArgTest extends TestHelper { throw new RuntimeException("test fails"); } - // Test via JAVA_OPTIONS -/* + // Test via JDK_JAVA_OPTIONS Map env = new HashMap<>(); String cmd = "-Dtest.src=" + TEST_SOURCES_DIR.getAbsolutePath() + " -Dtest.classes=" + TEST_CLASSES_DIR.getAbsolutePath() + " -cp " + TEST_CLASSES_DIR.getAbsolutePath() + " I18NArgTest " + unicodeStr + " " + hexValue; - env.put("JAVA_OPTIONS", cmd); + env.put("JDK_JAVA_OPTIONS", cmd); tr = doExec(env, javaCmd); System.out.println(tr.testOutput); if (!tr.isOK()) { System.err.println(tr); throw new RuntimeException("test fails"); } -*/ } static void testCharacters(String... args) { diff --git a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java index a774fc7427f..0eef57b33fb 100644 --- a/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java +++ b/jdk/test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java @@ -30,6 +30,8 @@ package jdk.internal.module; public final class SystemModules { public static final String[] MODULE_NAMES = new String[0]; + public static int PACKAGES_IN_BOOT_LAYER = 1024; + public static boolean hasSplitPackages() { return true; } diff --git a/langtools/.hgtags b/langtools/.hgtags index b4acf327b61..b0dfd872ddc 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -397,3 +397,4 @@ e5a42ddaf633fde14b983f740ae0e7e490741fd1 jdk-9+150 5b6f12de6f9167a582fa2c6ac54e69c591b09e68 jdk-9+152 03f48cd283f5dd6b7153fd7e0cf2df8582b14391 jdk-9+153 6a9dd3d893b0a493a3e5d8d392815b5ee76a02d9 jdk-9+154 +dfcfdb2db85f1bb434209f56ca557ea6f9830aa8 jdk-9+155 diff --git a/langtools/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java b/langtools/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java index 9dfbcb22f43..0a8287b8b4b 100644 --- a/langtools/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java +++ b/langtools/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java @@ -83,7 +83,7 @@ public abstract class AbstractProcessor implements Processor { if (so == null) return Collections.emptySet(); else - return arrayToSet(so.value()); + return arrayToSet(so.value(), false); } /** @@ -92,21 +92,31 @@ public abstract class AbstractProcessor implements Processor { * same set of strings as the annotation. If the class is not so * annotated, an empty set is returned. * + * If the {@link ProcessingEvironment#getSourceVersion source + * version} does not support modules, in other words if it is less + * than or equal to {@link SourceVersion#RELEASE_8 RELEASE_8}, + * then any leading {@link Processor#getSupportedAnnotationTypes + * module prefixes} are stripped from the names. + * * @return the names of the annotation types supported by this * processor, or an empty set if none */ public Set getSupportedAnnotationTypes() { SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class); + boolean initialized = isInitialized(); if (sat == null) { - if (isInitialized()) + if (initialized) processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "No SupportedAnnotationTypes annotation " + "found on " + this.getClass().getName() + ", returning an empty set."); return Collections.emptySet(); + } else { + boolean stripModulePrefixes = + initialized && + processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_8) <= 0; + return arrayToSet(sat.value(), stripModulePrefixes); } - else - return arrayToSet(sat.value()); } /** @@ -185,11 +195,18 @@ public abstract class AbstractProcessor implements Processor { return initialized; } - private static Set arrayToSet(String[] array) { + private static Set arrayToSet(String[] array, + boolean stripModulePrefixes) { assert array != null; Set set = new HashSet<>(array.length); - for (String s : array) + for (String s : array) { + if (stripModulePrefixes) { + int index = s.indexOf('/'); + if (index != -1) + s = s.substring(index + 1); + } set.add(s); + } return Collections.unmodifiableSet(set); } } diff --git a/langtools/src/java.compiler/share/classes/javax/annotation/processing/Filer.java b/langtools/src/java.compiler/share/classes/javax/annotation/processing/Filer.java index 97979b932c2..9a81988478e 100644 --- a/langtools/src/java.compiler/share/classes/javax/annotation/processing/Filer.java +++ b/langtools/src/java.compiler/share/classes/javax/annotation/processing/Filer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -264,7 +264,7 @@ public interface Filer { * @param moduleAndPkg module and/or package relative to which the file * should be named, or the empty string if none * @param relativeName final pathname components of the file - * @param originatingElements type or package elements causally + * @param originatingElements type or package or module elements causally * associated with the creation of this file, may be elided or * {@code null} * @return a {@code FileObject} to write the new resource diff --git a/langtools/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java b/langtools/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java index 30a13886f04..95855219258 100644 --- a/langtools/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java +++ b/langtools/src/java.compiler/share/classes/javax/annotation/processing/FilerException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.io.IOException; * Indicates a {@link Filer} detected an attempt to open a file that * would violate the guarantees provided by the {@code Filer}. Those * guarantees include not creating the same file more than once, not - * creating multiple files corresponding to the same type, and not + * creating multiple files corresponding to the same type or package, and not * creating files for types with invalid names. * * @author Joseph D. Darcy diff --git a/langtools/src/java.compiler/share/classes/javax/annotation/processing/Processor.java b/langtools/src/java.compiler/share/classes/javax/annotation/processing/Processor.java index 9eae468d4ef..e7a8278dce2 100644 --- a/langtools/src/java.compiler/share/classes/javax/annotation/processing/Processor.java +++ b/langtools/src/java.compiler/share/classes/javax/annotation/processing/Processor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,7 +194,7 @@ import javax.lang.model.SourceVersion; *

      The {@link Filer} interface discusses restrictions on how * processors can operate on files. * - *

      Note that implementors of this interface may find it convenient + * @apiNote Implementors of this interface may find it convenient * to extend {@link AbstractProcessor} rather than implementing this * interface directly. * @@ -254,6 +254,14 @@ public interface Processor { * a.B} which reside in different modules. To only support {@code * a.B} in the {@code Foo} module, instead use {@code "Foo/a.B"}. * + * If a module name is included, only an annotation in that module + * is matched. In particular, if a module name is given in an + * environment where modules are not supported, such as an + * annotation processing environment configured for a {@linkplain + * javax.annotation.processing.ProcessingEnvironment#getSourceVersion + * source version} without modules, then the annotation types with + * a module name do not match. + * * Finally, {@code "*"} by itself represents the set of all * annotation types, including the empty set. Note that a * processor should not claim {@code "*"} unless it is actually @@ -280,6 +288,14 @@ public interface Processor { * where TypeName is as defined in * The Java™ Language Specification. * + * @apiNote When running in an environment which supports modules, + * processors are encouraged to include the module prefix when + * describing their supported annotation types. The method {@link + * AbstractProcessor.getSupportedAnnotationTypes + * AbstractProcessor.getSupportedAnnotationTypes} provides support + * for stripping off the module prefix when running in an + * environment without modules. + * * @return the names of the annotation types supported by this processor * @see javax.annotation.processing.SupportedAnnotationTypes * @jls 3.8 Identifiers @@ -315,7 +331,7 @@ public interface Processor { * is returned, the annotation types are unclaimed and subsequent * processors may be asked to process them. A processor may * always return the same boolean value or may vary the result - * based on chosen criteria. + * based on its own chosen criteria. * *

      The input set will be empty if the processor supports {@code * "*"} and the root elements have no annotations. A {@code @@ -343,8 +359,8 @@ public interface Processor { *

      Since incomplete programs are being modeled, some of the * parameters may only have partial information or may be {@code * null}. At least one of {@code element} and {@code userText} - * must be non-{@code null}. If {@code element} is non-{@code - * null}, {@code annotation} and {@code member} may be {@code + * must be non-{@code null}. If {@code element} is non-{@code null}, + * {@code annotation} and {@code member} may be {@code * null}. Processors may not throw a {@code NullPointerException} * if some parameters are {@code null}; if a processor has no * completions to offer based on the provided information, an diff --git a/langtools/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java b/langtools/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java index f2a94f0b19f..f138a81cafd 100644 --- a/langtools/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java +++ b/langtools/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public interface RoundEnvironment { boolean errorRaised(); /** - * Returns the root elements for annotation processing generated + * Returns the {@linkplain Processor root elements} for annotation processing generated * by the prior round. * * @return the root elements for annotation processing generated diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java b/langtools/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java index a80a6eab7d1..a32e65eb2b4 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ import javax.lang.model.type.*; * * If there are multiple annotations of type AT present on * C, then if AT is repeatable annotation type, an - * annotation of type ATC is implicitly declared on C. + * annotation of type ATC is {@linkplain javax.lang.model.util.Elements#getOrigin(AnnotatedConstruct, AnnotationMirror) implicitly declared} on C. * *

    • A representation of A appears in the executable output * for C, such as the {@code RuntimeVisibleAnnotations} or diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java b/langtools/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java index 0eb1b3a7992..34971fab11e 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/UnknownEntityException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,9 @@ package javax.lang.model; * this exception may be thrown by visitors to indicate that the * visitor was created for a prior version of the language. * - *

      A common superclass for those exceptions allows a single catch - * block to have code handling them uniformly. + * @apiNote A common superclass for exceptions specific to different + * kinds of unknown entities allows a single catch block to easily + * provide uniform handling of those related conditions. * * @author Joseph D. Darcy * @see javax.lang.model.element.UnknownElementException diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/Element.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/Element.java index 3c00e68355c..e1b7502ae0c 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/Element.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/Element.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +37,7 @@ import javax.lang.model.util.*; /** - * Represents a program element such as a package, class, or method. + * Represents a program element such as a module, package, class, or method. * Each element represents a static, language-level construct * (and not, for example, a runtime construct of the virtual machine). * @@ -139,7 +139,7 @@ public interface Element extends javax.lang.model.AnnotatedConstruct { * *

    • If this is a {@linkplain * PackageElement#getEnclosingElement package}, its module is - * returned. + * returned if such a module exists. Otherwise, {@code null} is returned. * *
    • If this is a {@linkplain * TypeParameterElement#getEnclosingElement type parameter}, @@ -176,11 +176,14 @@ public interface Element extends javax.lang.model.AnnotatedConstruct { * A {@linkplain ModuleElement#getEnclosedElements module} * encloses packages within it. * + * Enclosed elements may include implicitly declared {@linkplain + * Elements.Origin#MANDATED mandated} elements. + * * Other kinds of elements are not currently considered to enclose * any elements; however, that may change as this API or the * programming language evolves. * - *

      Note that elements of certain kinds can be isolated using + * @apiNote Elements of certain kinds can be isolated using * methods in {@link ElementFilter}. * * @return the enclosed elements, or an empty list if none @@ -197,7 +200,7 @@ public interface Element extends javax.lang.model.AnnotatedConstruct { * Returns {@code true} if the argument represents the same * element as {@code this}, or {@code false} otherwise. * - *

      Note that the identity of an element involves implicit state + * @apiNote The identity of an element involves implicit state * not directly accessible from the element's methods, including * state about the presence of unrelated types. Element objects * created by different implementations of these interfaces should diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java index 40e7bc63ebf..cf3f6b1992a 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java @@ -37,17 +37,18 @@ import java.util.List; public interface ModuleElement extends Element, QualifiedNameable { /** - * Returns the fully qualified name of this module. + * Returns the fully qualified name of this module. For an + * {@linkplain #isUnnamed() unnamed module}, an empty name is returned. * - * @return the qualified name of this module, or an + * @return the fully qualified name of this module, or an * empty name if this is an unnamed module */ @Override Name getQualifiedName(); /** - * Returns the simple name of this module. For an unnamed - * module, an empty name is returned. + * Returns the simple name of this module. For an {@linkplain + * #isUnnamed() unnamed module}, an empty name is returned. * * @return the simple name of this module or an empty name if * this is an unnamed module diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java index b618c48f07d..1502255ff67 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,25 +89,29 @@ public enum NestingKind { /** * A type that is a named member of another type. + * @jls 8.5 Member Type Declarations */ MEMBER, /** * A named type declared within a construct other than a type. + * @jls 14.3 Local Class Declarations */ LOCAL, /** * A type without a name. + * @jls 15.9.5 Anonymous Class Declarations */ ANONYMOUS; /** * Does this constant correspond to a nested type element? * A nested type element is any that is not top-level. - * An inner type element is any nested type element that + * More specifically, an inner type element is any nested type element that * is not {@linkplain Modifier#STATIC static}. * @return whether or not the constant is nested + * @jls 14.3 Inner Classes and Enclosing Instances */ public boolean isNested() { return this != TOP_LEVEL; diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java index f319d3185be..6535c00e8de 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/PackageElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ public interface PackageElement extends Element, QualifiedNameable { /** * Returns the fully qualified name of this package. * This is also known as the package's canonical name. + * For an {@linkplain #isUnnamed() unnamed package}, an empty name is returned. * * @return the fully qualified name of this package, or an * empty name if this is an unnamed package @@ -50,8 +51,8 @@ public interface PackageElement extends Element, QualifiedNameable { Name getQualifiedName(); /** - * Returns the simple name of this package. For an unnamed - * package, an empty name is returned. + * Returns the simple name of this package. For an {@linkplain + * #isUnnamed() unnamed package}, an empty name is returned. * * @return the simple name of this package or an empty name if * this is an unnamed package @@ -82,9 +83,16 @@ public interface PackageElement extends Element, QualifiedNameable { boolean isUnnamed(); /** - * Returns the enclosing module. + * Returns the enclosing module if such a module exists; otherwise + * returns {@code null}. * - * @return the enclosing module + * One situation where a module does not exist for a package is if + * the environment does not include modules, such as an annotation + * processing environment configured for a {@linkplain + * javax.annotation.processing.ProcessingEnvironment#getSourceVersion + * source version} without modules. + * + * @return the enclosing module or {@code null} if no such module exists */ @Override Element getEnclosingElement(); diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java index 4ddb3147db8..55d9042bca8 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/Parameterizable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import java.util.List; */ public interface Parameterizable extends Element { /** - * Returns the formal type parameters of the type element in + * Returns the formal type parameters of an element in * declaration order. * * @return the formal type parameters, or an empty list diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java index 8f6d153b71a..73bcf1d8419 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,21 +63,25 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable * Returns the fields, methods, constructors, and member types * that are directly declared in this class or interface. * - * This includes any (implicit) default constructor and - * the implicit {@code values} and {@code valueOf} methods of an - * enum type. + * This includes any {@linkplain Elements.Origin#MANDATED + * mandated} elements such as the (implicit) default constructor + * and the implicit {@code values} and {@code valueOf} methods of + * an enum type. * - *

      Note that as a particular instance of the {@linkplain + * @apiNote As a particular instance of the {@linkplain * javax.lang.model.element general accuracy requirements} and the * ordering behavior required of this interface, the list of * enclosed elements will be returned in the natural order for the * originating source of information about the type. For example, * if the information about the type is originating from a source * file, the elements will be returned in source code order. - * (However, in that case the the ordering of synthesized - * elements, such as a default constructor, is not specified.) + * (However, in that case the the ordering of elements, such as a + * default constructor, is not specified.) * * @return the enclosed elements in proper order, or an empty list if none + * + * @jls 8.8.9 Default Constructor + * @jls 8.9.3 Enum Members */ @Override List getEnclosedElements(); diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java index a25204b35be..b6f1d6bc2d9 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownAnnotationValueException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,7 +79,7 @@ public class UnknownAnnotationValueException extends UnknownEntityException { /** * Returns the additional argument. * - * @return the additional argument + * @return the additional argument, or {@code null} if unavailable */ public Object getArgument() { return parameter; diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java index d5f87bb2269..6eeec9b5a60 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/UnknownElementException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ public class UnknownElementException extends UnknownEntityException { /** * Returns the additional argument. * - * @return the additional argument + * @return the additional argument, or {@code null} if unavailable */ public Object getArgument() { return parameter; diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/element/package-info.java b/langtools/src/java.compiler/share/classes/javax/lang/model/element/package-info.java index 967bde79cdb..857d231a309 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/element/package-info.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/element/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,14 +87,14 @@ * If a program is syntactically valid but erroneous in some other * fashion, any returned model must have no less information than if * all the method bodies in the program were replaced by {@code "throw - * new RuntimeException();"}. If a program refers to a missing type XYZ, + * new RuntimeException();"}. If a program refers to a missing type Xyz, * the returned model must contain no less information than if the - * declaration of type XYZ were assumed to be {@code "class XYZ {}"}, - * {@code "interface XYZ {}"}, {@code "enum XYZ {}"}, or {@code - * "@interface XYZ {}"}. If a program refers to a missing type {@code - * XYZ}, the returned model must contain no less - * information than if the declaration of XYZ were assumed to be - * {@code "class XYZ {}"} or {@code "interface XYZ}, the returned model must contain no less + * information than if the declaration of Xyz were assumed to be + * {@code "class Xyz {}"} or {@code "interface Xyz {}"} * *

      Unless otherwise specified in a particular implementation, the diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/type/IntersectionType.java b/langtools/src/java.compiler/share/classes/javax/lang/model/type/IntersectionType.java index 9bd96711b6b..359200d961e 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/type/IntersectionType.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/type/IntersectionType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,14 +33,12 @@ import java.util.List; *

      An intersection type can be either implicitly or explicitly * declared in a program. For example, the bound of the type parameter * {@code } is an (implicit) intersection - * type. As of {@link javax.lang.model.SourceVersion#RELEASE_8 - * RELEASE_8}, this is represented by an {@code IntersectionType} with + * type. This is represented by an {@code IntersectionType} with * {@code Number} and {@code Runnable} as its bounds. * - * @implNote Also as of {@link - * javax.lang.model.SourceVersion#RELEASE_8 RELEASE_8}, in the - * reference implementation an {@code IntersectionType} is used to - * model the explicit target type of a cast expression. + * @implNote In the reference implementation an {@code + * IntersectionType} is used to model the explicit target type of a + * cast expression. * * @since 1.8 */ @@ -49,7 +47,7 @@ public interface IntersectionType extends TypeMirror { /** * Return the bounds comprising this intersection type. * - * @return the bounds of this intersection types. + * @return the bounds of this intersection type */ List getBounds(); } diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/type/NoType.java b/langtools/src/java.compiler/share/classes/javax/lang/model/type/NoType.java index 5cbfbfaf998..1114722a601 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/type/NoType.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/type/NoType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import javax.lang.model.element.ExecutableElement; *

        *
      • {@link TypeKind#VOID VOID} - corresponds to the keyword {@code void}. *
      • {@link TypeKind#PACKAGE PACKAGE} - the pseudo-type of a package element. + *
      • {@link TypeKind#MODULE MODULE} - the pseudo-type of a module element. *
      • {@link TypeKind#NONE NONE} - used in other cases * where no actual type is appropriate; for example, the superclass * of {@code java.lang.Object}. diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnionType.java b/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnionType.java index 92cfb34dd8c..97d7014bb6e 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnionType.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnionType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. * 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,9 +30,8 @@ import java.util.List; /** * Represents a union type. * - * As of the {@link javax.lang.model.SourceVersion#RELEASE_7 - * RELEASE_7} source version, union types can appear as the type - * of a multi-catch exception parameter. + * Union types can appear as the type of a multi-catch exception + * parameter. * * @since 1.7 */ diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java b/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java index babeac9dd34..f710bf61028 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/type/UnknownTypeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ public class UnknownTypeException extends UnknownEntityException { /** * Returns the additional argument. * - * @return the additional argument + * @return the additional argument, or {@code null} if unavailable */ public Object getArgument() { return parameter; diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java b/langtools/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java index 893a124c031..db5c9873aca 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,15 +55,6 @@ import javax.lang.model.element.ModuleElement.UsesDirective; * arguments to methods in this class, a {@code NullPointerException} * will be thrown. * - *

        Note that a static import statement can make the text of - * calls to the methods in this class more concise; for example: - * - *

        - *     import static javax.lang.model.util.ElementFilter.*;
        - *     ...
        - *         {@code List} fs = fieldsIn(someClass.getEnclosedElements());
        - * 
        - * * @author Joseph D. Darcy * @author Scott Seligman * @author Peter von der Ahé diff --git a/langtools/src/java.compiler/share/classes/javax/lang/model/util/Elements.java b/langtools/src/java.compiler/share/classes/javax/lang/model/util/Elements.java index a2c92f46cc6..c8038b7b39b 100644 --- a/langtools/src/java.compiler/share/classes/javax/lang/model/util/Elements.java +++ b/langtools/src/java.compiler/share/classes/javax/lang/model/util/Elements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,12 +59,17 @@ public interface Elements { /** * Returns a package given its fully qualified name, as seen from the given module. * + * @implSpec The default implementation of this method returns + * {@code null}. + * * @param name fully qualified package name, or an empty string for an unnamed package * @param module module relative to which the lookup should happen * @return the specified package, or {@code null} if it cannot be found * @since 9 */ - PackageElement getPackageElement(ModuleElement module, CharSequence name); + default PackageElement getPackageElement(ModuleElement module, CharSequence name) { + return null; + } /** * Returns a type element given its canonical name if the type element is unique in the environment. @@ -79,12 +84,17 @@ public interface Elements { /** * Returns a type element given its canonical name, as seen from the given module. * + * @implSpec The default implementation of this method returns + * {@code null}. + * * @param name the canonical name * @param module module relative to which the lookup should happen * @return the named type element, or {@code null} if it cannot be found * @since 9 */ - TypeElement getTypeElement(ModuleElement module, CharSequence name); + default TypeElement getTypeElement(ModuleElement module, CharSequence name) { + return null; + } /** * Returns a module element given its fully qualified name. @@ -95,11 +105,16 @@ public interface Elements { * javax.annotation.processing.ProcessingEnvironment#getSourceVersion * source version} without modules. * + * @implSpec The default implementation of this method returns + * {@code null}. + * * @param name the name * @return the named module element, or {@code null} if it cannot be found * @since 9 */ - ModuleElement getModuleElement(CharSequence name); + default ModuleElement getModuleElement(CharSequence name) { + return null; + } /** * Returns the values of an annotation's elements, including defaults. @@ -267,6 +282,7 @@ public interface Elements { * multiple annotations of a repeatable annotation type. * * @jls 8.8.9 Default Constructor + * @jls 8.9.3 Enum Members * @jls 9.6.3 Repeatable Annotation Types * @jls 9.7.5 Multiple Annotations of the Same Type */ @@ -337,18 +353,23 @@ public interface Elements { * javax.annotation.processing.ProcessingEnvironment#getSourceVersion * source version} without modules. * + * @implSpec The default implementation of this method returns + * {@code null}. + * * @param type the element being examined * @return the module of an element * @since 9 */ - ModuleElement getModuleOf(Element type); + default ModuleElement getModuleOf(Element type) { + return null; + } /** * Returns all members of a type element, whether inherited or * declared directly. For a class the result also includes its * constructors, but not local or anonymous classes. * - *

        Note that elements of certain kinds can be isolated using + * @apiNote Elements of certain kinds can be isolated using * methods in {@link ElementFilter}. * * @param type the type being examined diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/source/tree/ImportTree.java b/langtools/src/jdk.compiler/share/classes/com/sun/source/tree/ImportTree.java index 0b0c19274f3..3235910ca0f 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/source/tree/ImportTree.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/source/tree/ImportTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +26,7 @@ package com.sun.source.tree; /** - * A tree node for an import statement. + * A tree node for an import declaration. * * For example: *

        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
        index e124d3ff37f..8a050922259 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -118,6 +118,7 @@ public class Lint
                     if (source.compareTo(Source.JDK1_9) >= 0) {
                         values.add(LintCategory.DEP_ANN);
                     }
        +            values.add(LintCategory.OPENS);
                     values.add(LintCategory.MODULE);
                     values.add(LintCategory.REMOVAL);
                 }
        @@ -210,6 +211,11 @@ public class Lint
                  */
                 MODULE("module"),
         
        +        /**
        +         * Warn about issues regarding module opens.
        +         */
        +        OPENS("opens"),
        +
                 /**
                  * Warn about issues relating to use of command line options
                  */
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
        index 07f7975c1c3..353bb1fb7a8 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
        @@ -2947,6 +2947,14 @@ public class Attr extends JCTree.Visitor {
                         return;
                     }
         
        +            if (!env.info.isSpeculative && that.getMode() == JCMemberReference.ReferenceMode.NEW) {
        +                Type enclosingType = exprType.getEnclosingType();
        +                if (enclosingType != null && enclosingType.hasTag(CLASS)) {
        +                    // Check for the existence of an apropriate outer instance
        +                    rs.resolveImplicitThis(that.pos(), env, exprType);
        +                }
        +            }
        +
                     if (resultInfo.checkContext.deferredAttrContext().mode == AttrMode.CHECK) {
         
                         if (that.getMode() == ReferenceMode.INVOKE &&
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
        index 742cdcc03d7..117da713ead 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
        @@ -3876,4 +3876,14 @@ public class Check {
                 }
             }
         
        +    void checkPackageExistsForOpens(final DiagnosticPosition pos, PackageSymbol packge) {
        +        if (packge.members().isEmpty() &&
        +            ((packge.flags() & Flags.HAS_RESOURCE) == 0)) {
        +            deferredLintHandler.report(() -> {
        +                if (lint.isEnabled(LintCategory.OPENS))
        +                    log.warning(pos, Warnings.PackageEmptyOrNotFound(packge));
        +            });
        +        }
        +    }
        +
         }
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
        index a60ca6ceb92..c0e6543ba43 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java
        @@ -165,6 +165,7 @@ public class Modules extends JCTree.Visitor {
             private final boolean lintOptions;
         
             private Set rootModules = null;
        +    private final Set warnedMissing = new HashSet<>();
         
             public static Modules instance(Context context) {
                 Modules instance = context.get(Modules.class);
        @@ -525,7 +526,6 @@ public class Modules extends JCTree.Visitor {
                     ModuleSymbol msym = moduleFinder.findModule((ModuleSymbol) sym);
         
                     if (msym.kind == ERR) {
        -                log.error(Errors.ModuleNotFound(msym));
                         //make sure the module is initialized:
                         msym.directives = List.nil();
                         msym.exports = List.nil();
        @@ -674,6 +674,7 @@ public class Modules extends JCTree.Visitor {
                     ModuleSymbol msym = lookupModule(tree.moduleName);
                     if (msym.kind != MDL) {
                         log.error(tree.moduleName.pos(), Errors.ModuleNotFound(msym));
        +                warnedMissing.add(msym);
                     } else if (allRequires.contains(msym)) {
                         log.error(tree.moduleName.pos(), Errors.DuplicateRequires(msym));
                     } else {
        @@ -695,9 +696,6 @@ public class Modules extends JCTree.Visitor {
                     PackageSymbol packge = syms.enterPackage(sym, name);
                     attr.setPackageSymbols(tree.qualid, packge);
         
        -            if (tree.hasTag(Tag.OPENS) && sym.flags.contains(ModuleFlags.OPEN)) {
        -                log.error(tree.pos(), Errors.NoOpensUnlessStrong);
        -            }
                     List exportsForPackage = allExports.computeIfAbsent(packge, p -> List.nil());
                     for (ExportsDirective d : exportsForPackage) {
                         reportExportsConflict(tree, packge);
        @@ -898,10 +896,7 @@ public class Modules extends JCTree.Visitor {
         
                 @Override
                 public void visitOpens(JCOpens tree) {
        -            if (tree.directive.packge.members().isEmpty() &&
        -                ((tree.directive.packge.flags() & Flags.HAS_RESOURCE) == 0)) {
        -                log.error(tree.qualid.pos(), Errors.PackageEmptyOrNotFound(tree.directive.packge));
        -            }
        +            chk.checkPackageExistsForOpens(tree.qualid, tree.directive.packge);
                     msym.directives = msym.directives.prepend(tree.directive);
                 }
         
        @@ -931,6 +926,9 @@ public class Modules extends JCTree.Visitor {
                 public void visitProvides(JCProvides tree) {
                     Type st = attr.attribType(tree.serviceName, env, syms.objectType);
                     ClassSymbol service = (ClassSymbol) st.tsym;
        +            if (allProvides.containsKey(service)) {
        +                log.error(tree.serviceName.pos(), Errors.RepeatedProvidesForService(service));
        +            }
                     ListBuffer impls = new ListBuffer<>();
                     for (JCExpression implName : tree.implNames) {
                         Type it = attr.attribType(implName, env, syms.objectType);
        @@ -959,8 +957,6 @@ public class Modules extends JCTree.Visitor {
                             }
                         }
                         if (it.hasTag(CLASS)) {
        -                    // For now, we just check the pair (service-type, impl-type) is unique
        -                    // TODO, check only one provides per service type as well
                             if (allProvides.computeIfAbsent(service, s -> new HashSet<>()).add(impl)) {
                                 impls.append(impl);
                             } else {
        @@ -1183,26 +1179,44 @@ public class Modules extends JCTree.Visitor {
                 return allModules == null || allModules.contains(msym);
             }
         
        -    private Set computeTransitiveClosure(Iterable base, Set observable) {
        -        List todo = List.nil();
        +    private Set computeTransitiveClosure(Set base, Set observable) {
        +        List primaryTodo = List.nil();
        +        List secondaryTodo = List.nil();
         
                 for (ModuleSymbol ms : base) {
        -            todo = todo.prepend(ms);
        +            primaryTodo = primaryTodo.prepend(ms);
                 }
         
                 Set result = new LinkedHashSet<>();
                 result.add(syms.java_base);
         
        -        while (todo.nonEmpty()) {
        -            ModuleSymbol current = todo.head;
        -            todo = todo.tail;
        +        while (primaryTodo.nonEmpty() || secondaryTodo.nonEmpty()) {
        +            ModuleSymbol current;
        +            boolean isPrimaryTodo;
        +            if (primaryTodo.nonEmpty()) {
        +                current = primaryTodo.head;
        +                primaryTodo = primaryTodo.tail;
        +                isPrimaryTodo = true;
        +            } else {
        +                current = secondaryTodo.head;
        +                secondaryTodo = secondaryTodo.tail;
        +                isPrimaryTodo = false;
        +            }
                     if (observable != null && !observable.contains(current))
                         continue;
                     if (!result.add(current) || current == syms.unnamedModule || ((current.flags_field & Flags.AUTOMATIC_MODULE) != 0))
                         continue;
                     current.complete();
        +            if (current.kind == ERR && isPrimaryTodo && warnedMissing.add(current)) {
        +                log.error(Errors.ModuleNotFound(current));
        +            }
                     for (RequiresDirective rd : current.requires) {
        -                todo = todo.prepend(rd.module);
        +                if (rd.module == syms.java_base) continue;
        +                if ((rd.isTransitive() && isPrimaryTodo) || base.contains(current)) {
        +                    primaryTodo = primaryTodo.prepend(rd.module);
        +                } else {
        +                    secondaryTodo = secondaryTodo.prepend(rd.module);
        +                }
                     }
                 }
         
        @@ -1582,5 +1596,6 @@ public class Modules extends JCTree.Visitor {
             public void newRound() {
                 rootModules = null;
                 allModules = null;
        +        warnedMissing.clear();
             }
         }
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java
        index 9fe9611bbbe..b5a200f14d6 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java
        @@ -502,7 +502,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
             private final class ArchiveContainer implements Container {
                 private final Path archivePath;
                 private final FileSystem fileSystem;
        -        private final Map pathCache = new HashMap<>();
        +        private final Map packages;
         
                 public ArchiveContainer(Path archivePath) throws IOException, ProviderNotFoundException, SecurityException {
                     this.archivePath = archivePath;
        @@ -514,6 +514,21 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
                     } else {
                         this.fileSystem = FileSystems.newFileSystem(archivePath, null);
                     }
        +            packages = new HashMap<>();
        +            for (Path root : fileSystem.getRootDirectories()) {
        +                Files.walkFileTree(root, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE,
        +                        new SimpleFileVisitor() {
        +                            @Override
        +                            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
        +                                if (isValid(dir.getFileName())) {
        +                                    packages.put(new RelativeDirectory(root.relativize(dir).toString()), dir);
        +                                    return FileVisitResult.CONTINUE;
        +                                } else {
        +                                    return FileVisitResult.SKIP_SUBTREE;
        +                                }
        +                            }
        +                        });
        +            }
                 }
         
                 /**
        @@ -526,7 +541,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
                                  Set fileKinds,
                                  boolean recurse,
                                  ListBuffer resultList) throws IOException {
        -            Path resolvedSubdirectory = resolvePath(subdirectory);
        +            Path resolvedSubdirectory = packages.get(subdirectory);
         
                     if (resolvedSubdirectory == null)
                         return ;
        @@ -544,18 +559,6 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
                                     }
                                 }
         
        -                        boolean isValid(Path fileName) {
        -                            if (fileName == null) {
        -                                return true;
        -                            } else {
        -                                String name = fileName.toString();
        -                                if (name.endsWith("/")) {
        -                                    name = name.substring(0, name.length() - 1);
        -                                }
        -                                return SourceVersion.isIdentifier(name);
        -                            }
        -                        }
        -
                                 @Override
                                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                                     if (attrs.isRegularFile() && fileKinds.contains(getKind(file.getFileName().toString()))) {
        @@ -569,27 +572,29 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil
         
                 }
         
        -        @Override
        -        public JavaFileObject getFileObject(Path userPath, RelativeFile name) throws IOException {
        -            Path p = resolvePath(name);
        -            if (p != null)
        -                return PathFileObject.forJarPath(JavacFileManager.this, p, userPath);
        -
        -            return null;
        +        private boolean isValid(Path fileName) {
        +            if (fileName == null) {
        +                return true;
        +            } else {
        +                String name = fileName.toString();
        +                if (name.endsWith("/")) {
        +                    name = name.substring(0, name.length() - 1);
        +                }
        +                return SourceVersion.isIdentifier(name);
        +            }
                 }
         
        -        private synchronized Path resolvePath(RelativePath path) {
        -            if (!pathCache.containsKey(path)) {
        -                Path relativePath = path.resolveAgainst(fileSystem);
        -
        -                if (!Files.exists(relativePath)) {
        -                    relativePath = null;
        +        @Override
        +        public JavaFileObject getFileObject(Path userPath, RelativeFile name) throws IOException {
        +            RelativeDirectory root = name.dirname();
        +            Path packagepath = packages.get(root);
        +            if (packagepath != null) {
        +                Path relpath = packagepath.resolve(name.basename());
        +                if (Files.exists(relpath)) {
        +                    return PathFileObject.forJarPath(JavacFileManager.this, relpath, userPath);
                         }
        -
        -                pathCache.put(path, relativePath);
        -                return relativePath;
                     }
        -            return pathCache.get(path);
        +            return null;
                 }
         
                 @Override
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
        index f0fa2277d44..e14fb7d5eee 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/Locations.java
        @@ -43,6 +43,7 @@ import java.nio.file.InvalidPathException;
         import java.nio.file.Path;
         import java.nio.file.Paths;
         import java.nio.file.ProviderNotFoundException;
        +import java.nio.file.spi.FileSystemProvider;
         import java.util.ArrayList;
         import java.util.Arrays;
         import java.util.Collection;
        @@ -1119,8 +1120,12 @@ public class Locations {
                         }
         
                         if (p.getFileName().toString().endsWith(".jar") && fsInfo.exists(p)) {
        -                    URI uri = URI.create("jar:" + p.toUri());
        -                    try (FileSystem fs = FileSystems.newFileSystem(uri, fsEnv, null)) {
        +                    FileSystemProvider jarFSProvider = fsInfo.getJarFSProvider();
        +                    if (jarFSProvider == null) {
        +                        log.error(Errors.NoZipfsForArchive(p));
        +                        return null;
        +                    }
        +                    try (FileSystem fs = jarFSProvider.newFileSystem(p, fsEnv)) {
                                 Path moduleInfoClass = fs.getPath("module-info.class");
                                 if (Files.exists(moduleInfoClass)) {
                                     String moduleName = readModuleName(moduleInfoClass);
        @@ -1132,9 +1137,6 @@ public class Locations {
                             } catch (IOException e) {
                                 log.error(Errors.LocnCantReadFile(p));
                                 return null;
        -                    } catch (ProviderNotFoundException e) {
        -                        log.error(Errors.NoZipfsForArchive(p));
        -                        return null;
                             }
         
                             //automatic module:
        @@ -1177,8 +1179,12 @@ public class Locations {
                                 // workaround for now
                                 FileSystem fs = fileSystems.get(p);
                                 if (fs == null) {
        -                            URI uri = URI.create("jar:" + p.toUri());
        -                            fs = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
        +                            FileSystemProvider jarFSProvider = fsInfo.getJarFSProvider();
        +                            if (jarFSProvider == null) {
        +                                log.error(Errors.LocnCantReadFile(p));
        +                                return null;
        +                            }
        +                            fs = jarFSProvider.newFileSystem(p, Collections.emptyMap());
                                     try {
                                         Path moduleInfoClass = fs.getPath("classes/module-info.class");
                                         String moduleName = readModuleName(moduleInfoClass);
        @@ -1194,7 +1200,7 @@ public class Locations {
                                 }
                             } catch (ModuleNameReader.BadClassFile e) {
                                 log.error(Errors.LocnBadModuleInfo(p));
        -                    } catch (IOException | ProviderNotFoundException e) {
        +                    } catch (IOException e) {
                                 log.error(Errors.LocnCantReadFile(p));
                                 return null;
                             }
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
        index 72008b2cb0b..8f0819e0359 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java
        @@ -45,6 +45,7 @@ import javax.lang.model.element.ElementVisitor;
         import javax.tools.DiagnosticListener;
         import javax.tools.JavaFileManager;
         import javax.tools.JavaFileObject;
        +import javax.tools.JavaFileObject.Kind;
         import javax.tools.StandardLocation;
         
         import com.sun.source.util.TaskEvent;
        @@ -623,7 +624,8 @@ public class JavaCompiler {
                         keepComments = true;
                         genEndPos = true;
                     }
        -            Parser parser = parserFactory.newParser(content, keepComments(), genEndPos, lineDebugInfo);
        +            Parser parser = parserFactory.newParser(content, keepComments(), genEndPos,
        +                                lineDebugInfo, filename.isNameCompatible("module-info", Kind.SOURCE));
                     tree = parser.parseCompilationUnit();
                     if (verbose) {
                         log.printVerbose("parsing.done", Long.toString(elapsed(msec)));
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java
        index 7d89af6cbe7..465af2f6c8f 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java
        @@ -288,7 +288,9 @@ public class JavacElements implements Elements {
                                            List trees) {
                 for (Attribute.Compound anno : annos) {
                     for (JCAnnotation tree : trees) {
        -                JCTree match = matchAnnoToTree(findme, anno, tree);
        +                if (tree.type.tsym != anno.type.tsym)
        +                    continue;
        +                JCTree match = matchAttributeToTree(findme, anno, tree);
                         if (match != null)
                             return match;
                     }
        @@ -297,15 +299,15 @@ public class JavacElements implements Elements {
             }
         
             /**
        -     * Returns the tree for an annotation given an Attribute to
        -     * search (recursively) and its corresponding tree.
        +     * Returns the tree for an attribute given an enclosing attribute to
        +     * search (recursively) and the enclosing attribute's corresponding tree.
              * Returns null if the tree cannot be found.
              */
        -    private JCTree matchAnnoToTree(final Attribute.Compound findme,
        -                                   final Attribute attr,
        -                                   final JCTree tree) {
        +    private JCTree matchAttributeToTree(final Attribute findme,
        +                                        final Attribute attr,
        +                                        final JCTree tree) {
                 if (attr == findme)
        -            return (tree.type.tsym == findme.type.tsym) ? tree : null;
        +            return tree;
         
                 class Vis implements Attribute.Visitor {
                     JCTree result = null;
        @@ -317,7 +319,7 @@ public class JavacElements implements Elements {
                         for (Pair pair : anno.values) {
                             JCExpression expr = scanForAssign(pair.fst, tree);
                             if (expr != null) {
        -                        JCTree match = matchAnnoToTree(findme, pair.snd, expr);
        +                        JCTree match = matchAttributeToTree(findme, pair.snd, expr);
                                 if (match != null) {
                                     result = match;
                                     return;
        @@ -326,16 +328,19 @@ public class JavacElements implements Elements {
                         }
                     }
                     public void visitArray(Attribute.Array array) {
        -                if (tree.hasTag(NEWARRAY) &&
        -                        types.elemtype(array.type).tsym == findme.type.tsym) {
        -                    List elems = ((JCNewArray) tree).elems;
        +                if (tree.hasTag(NEWARRAY)) {
        +                    List elems = ((JCNewArray)tree).elems;
                             for (Attribute value : array.values) {
        -                        if (value == findme) {
        -                            result = elems.head;
        +                        JCTree match = matchAttributeToTree(findme, value, elems.head);
        +                        if (match != null) {
        +                            result = match;
                                     return;
                                 }
                                 elems = elems.tail;
                             }
        +                } else if (array.values.length == 1) {
        +                    // the tree may not be a NEWARRAY for single-element array initializers
        +                    result = matchAttributeToTree(findme, array.values[0], tree);
                         }
                     }
                     public void visitEnum(Attribute.Enum e) {
        @@ -710,10 +715,15 @@ public class JavacElements implements Elements {
                 if (annoTree == null)
                     return elemTreeTop;
         
        -        // 6388543: if v != null, we should search within annoTree to find
        -        // the tree matching v. For now, we ignore v and return the tree of
        -        // the annotation.
        -        return new Pair<>(annoTree, elemTreeTop.snd);
        +        if (v == null)
        +            return new Pair<>(annoTree, elemTreeTop.snd);
        +
        +        JCTree valueTree = matchAttributeToTree(
        +                cast(Attribute.class, v), cast(Attribute.class, a), annoTree);
        +        if (valueTree == null)
        +            return new Pair<>(annoTree, elemTreeTop.snd);
        +
        +        return new Pair<>(valueTree, elemTreeTop.snd);
             }
         
             /**
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
        index 0d5be54a68e..4a08bdd9d13 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
        @@ -70,6 +70,10 @@ public class JavacParser implements Parser {
              */
             private static final int infixPrecedenceLevels = 10;
         
        +    /** Is the parser instantiated to parse a module-info file ?
        +     */
        +    private final boolean parseModuleInfo;
        +
             /** The scanner used for lexical analysis.
              */
             protected Lexer S;
        @@ -135,13 +139,24 @@ public class JavacParser implements Parser {
                 CATCH_CLAUSE {public JCTree doRecover(JavacParser parser) { return parser.catchClause(); }}
             }
         
        +    /** Construct a parser from a given scanner, tree factory and log.
        +     */
        +    protected JavacParser(ParserFactory fac,
        +                          Lexer S,
        +                          boolean keepDocComments,
        +                          boolean keepLineMap,
        +                          boolean keepEndPositions) {
        +        this(fac, S, keepDocComments, keepLineMap, keepEndPositions, false);
        +
        +    }
             /** Construct a parser from a given scanner, tree factory and log.
              */
             protected JavacParser(ParserFactory fac,
                              Lexer S,
                              boolean keepDocComments,
                              boolean keepLineMap,
        -                     boolean keepEndPositions) {
        +                     boolean keepEndPositions,
        +                     boolean parseModuleInfo) {
                 this.S = S;
                 nextToken(); // prime the pump
                 this.F = fac.F;
        @@ -165,6 +180,7 @@ public class JavacParser implements Parser {
                 this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
                 this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
                 this.keepDocComments = keepDocComments;
        +        this.parseModuleInfo = parseModuleInfo;
                 docComments = newDocCommentTable(keepDocComments, fac);
                 this.keepLineMap = keepLineMap;
                 this.errorTree = F.Erroneous();
        @@ -3347,8 +3363,13 @@ public class JavacParser implements Parser {
                     } else {
                         errs = List.of(mods);
                     }
        -            return toP(F.Exec(syntaxError(pos, errs, "expected3",
        -                                          CLASS, INTERFACE, ENUM)));
        +            final JCErroneous erroneousTree;
        +            if (parseModuleInfo) {
        +                erroneousTree = syntaxError(pos, errs, "expected.module.or.open");
        +            } else {
        +                erroneousTree = syntaxError(pos, errs, "expected3", CLASS, INTERFACE, ENUM);
        +            }
        +            return toP(F.Exec(erroneousTree));
                 }
             }
         
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java
        index 15e04bacf8d..23976e98070 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/ParserFactory.java
        @@ -81,7 +81,11 @@ public class ParserFactory {
             }
         
             public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) {
        +        return newParser(input, keepDocComments, keepEndPos, keepLineMap, false);
        +    }
        +
        +    public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) {
                 Lexer lexer = scannerFactory.newScanner(input, keepDocComments);
        -        return new JavacParser(this, lexer, keepDocComments, keepLineMap, keepEndPos);
        +        return new JavacParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, parseModuleInfo);
             }
         }
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
        index 08938c5c199..4a2ecb08aa4 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
        @@ -1671,14 +1671,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
                     if (s.equals("*")) {
                         return MatchingUtils.validImportStringToPattern(s);
                     }
        -            module = ".*/";
        +            module = allowModules ? ".*/" : "";
                     pkg = s;
                 } else {
                     module = Pattern.quote(s.substring(0, slash + 1));
                     pkg = s.substring(slash + 1);
                 }
                 if (MatchingUtils.isValidImportString(pkg)) {
        -            return Pattern.compile((allowModules ? module : "") + MatchingUtils.validImportStringToPatternString(pkg));
        +            return Pattern.compile(module + MatchingUtils.validImportStringToPatternString(pkg));
                 } else {
                     log.warning("proc.malformed.supported.string", s, p.getClass().getName());
                     return noMatches; // won't match any valid identifier
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
        index 2310d26281f..48243052b3c 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
        @@ -1895,6 +1895,9 @@ compiler.err.premature.eof=\
         compiler.err.expected.module=\
             ''module'' expected
         
        +compiler.err.expected.module.or.open=\
        +    ''module'' or ''open'' expected
        +
         compiler.err.dot.class.expected=\
             ''.class'' expected
         
        @@ -2882,6 +2885,10 @@ compiler.err.conflicting.opens.to.module=\
         compiler.err.no.opens.unless.strong=\
             ''opens'' only allowed in strong modules
         
        +# 0: symbol
        +compiler.err.repeated.provides.for.service=\
        +    multiple ''provides'' for service {0}
        +
         # 0: symbol, 1: symbol
         compiler.err.duplicate.provides=\
             duplicate provides: service {0}, implementation {1}
        @@ -2921,6 +2928,10 @@ compiler.err.service.implementation.no.args.constructor.not.public=\
         compiler.err.package.empty.or.not.found=\
             package is empty or does not exist: {0}
         
        +# 0: symbol
        +compiler.warn.package.empty.or.not.found=\
        +    package is empty or does not exist: {0}
        +
         compiler.err.no.output.dir=\
             no class output directory specified
         
        diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
        index 7a637a48d20..b92a26a1010 100644
        --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
        +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/javac.properties
        @@ -204,6 +204,9 @@ javac.opt.Xlint.desc.finally=\
         javac.opt.Xlint.desc.module=\
             Warn about module system related issues.
         
        +javac.opt.Xlint.desc.opens=\
        +    Warn about issues regarding module opens.
        +
         javac.opt.Xlint.desc.options=\
             Warn about issues relating to use of command line options.
         
        diff --git a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
        index 387534cf205..676672d774d 100644
        --- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
        +++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -1723,9 +1723,29 @@ public class HtmlDocletWriter extends HtmlDocWriter {
                             break main;
                         ch = text.charAt(currPos);
                     }
        -            if (ch == '>' && blockTags.contains(StringUtils.toLowerCase(text.substring(tagPos, currPos)))) {
        +            String tagFound = StringUtils.toLowerCase(text.substring(tagPos, currPos));
        +            if (blockTags.contains(tagFound)) {
                         result.append(text, startPos, lessThanPos);
        +                currPos = tagPos + tagFound.length();
        +                boolean foundGT = false;
        +                Character quoteKind = null;
        +                while (!foundGT) {
        +                    if (ch == '\"' || ch == '\'') {
        +                        if (quoteKind == null) {
        +                            quoteKind = ch;
        +                        } else if (quoteKind == ch) {
        +                            quoteKind = null;
        +                        }
        +                    }
        +                    if (ch == '>' && quoteKind == null) {
        +                        foundGT = true;
        +                    }
        +                    if (++currPos == len)
        +                        break;
        +                    ch = text.charAt(currPos);
        +                }
                         startPos = currPos + 1;
        +                currPos = startPos;
                     }
                     lessThanPos = text.indexOf('<', currPos);
                 }
        @@ -1740,6 +1760,10 @@ public class HtmlDocletWriter extends HtmlDocWriter {
                         ('1' <= ch && ch <= '6');
             }
         
        +    private static boolean isWhitespace(char ch) {
        +        return Character.isWhitespace(ch);
        +    }
        +
             /**
              * Add a link to the stylesheet file.
              *
        diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FrameOutputWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FrameOutputWriter.java
        index 12930a75ac9..de340fe3e1f 100644
        --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FrameOutputWriter.java
        +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FrameOutputWriter.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -29,10 +29,12 @@ import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
         import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
         import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
         import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
        +import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
         import jdk.javadoc.internal.doclets.toolkit.Content;
         import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
         import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
         import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
        +import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
         
         
         /**
        @@ -92,6 +94,15 @@ public class FrameOutputWriter extends HtmlDocletWriter {
                 Content frame = getFrameDetails();
                 HtmlTree body = new HtmlTree(HtmlTag.BODY);
                 body.addAttr(HtmlAttr.ONLOAD, "loadFrames()");
        +        String topFilePath = configuration.topFile.getPath();
        +        String javaScriptRefresh = "\nif (targetPage == \"\" || targetPage == \"undefined\")\n" +
        +                "     window.location.replace('" + topFilePath + "');\n";
        +        RawHtml scriptContent = new RawHtml(javaScriptRefresh.replace("\n", DocletConstants.NL));
        +        HtmlTree scriptTree = HtmlTree.SCRIPT();
        +        scriptTree.addContent(scriptContent);
        +        body.addContent(scriptTree);
        +        Content noScript = HtmlTree.NOSCRIPT(contents.noScriptMessage);
        +        body.addContent(noScript);
                 if (configuration.allowTag(HtmlTag.MAIN)) {
                     HtmlTree main = HtmlTree.MAIN(frame);
                     body.addContent(main);
        diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java
        index 91b0e039471..c9edc5824b7 100644
        --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java
        +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -74,6 +74,11 @@ public class PropertyWriterImpl extends AbstractMemberWriter
                 return memberTree;
             }
         
        +    @Override
        +    public boolean showTabs() {
        +        return false;
        +    }
        +
             /**
              * {@inheritDoc}
              */
        diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
        index 3b347675efa..4cc17b8a287 100644
        --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
        +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -1773,14 +1773,14 @@ public class Utils {
             /**
              * Returns a Comparator for index file presentations, and are sorted as follows.
              *  If comparing modules then simply compare the simple names,
        -     *  comparing packages then simply compare the qualified names, otherwise
        -     *  1. if equal, then compare the ElementKind ex: Module, Package, Interface etc.
        -     *  2. sort on simple names of entities
        -     *  3a. if equal and if the type is of ExecutableElement(Constructor, Methods),
        +     *  comparing packages then simply compare the qualified names, if comparing a package with a
        +     *  module/type/member then compare the FullyQualifiedName of the package
        +     *  with the SimpleName of the entity, otherwise
        +     *  1. compare the ElementKind ex: Module, Package, Interface etc.
        +     *  2a. if equal and if the type is of ExecutableElement(Constructor, Methods),
              *      a case insensitive comparison of parameter the type signatures
        -     *  3b. if equal, case sensitive comparison of the type signatures
        -     *  4. finally, if equal, compare the FQNs of the entities
        -     * Iff comparing packages then simply sort on qualified names.
        +     *  2b. if equal, case sensitive comparison of the type signatures
        +     *  3. finally, if equal, compare the FQNs of the entities
              * @return a comparator for index file use
              */
             public Comparator makeIndexUseComparator() {
        @@ -1788,8 +1788,10 @@ public class Utils {
                     /**
                      * Compare two given elements, if comparing two modules, return the
                      * comparison of SimpleName, if comparing two packages, return the
        -             * comparison of FullyQualifiedName, first sort on kinds, then on the
        -             * names, then on the parameters only if the type is an ExecutableElement,
        +             * comparison of FullyQualifiedName, if comparing a package with a
        +             * module/type/member then compare the FullyQualifiedName of the package
        +             * with the SimpleName of the entity, then sort on the kinds, then on
        +             * the parameters only if the type is an ExecutableElement,
                      * the parameters are compared and finally the qualified names.
                      *
                      * @param e1 - an element.
        @@ -1806,11 +1808,17 @@ public class Utils {
                         if (isPackage(e1) && isPackage(e2)) {
                             return compareFullyQualifiedNames(e1, e2);
                         }
        -                result = compareElementTypeKinds(e1, e2);
        +                if (isPackage(e1) || isPackage(e2)) {
        +                    result = (isPackage(e1))
        +                            ? compareStrings(getFullyQualifiedName(e1), getSimpleName(e2))
        +                            : compareStrings(getSimpleName(e1), getFullyQualifiedName(e2));
        +                } else {
        +                    result = compareNames(e1, e2);
        +                }
                         if (result != 0) {
                             return result;
                         }
        -                result = compareNames(e1, e2);
        +                result = compareElementTypeKinds(e1, e2);
                         if (result != 0) {
                             return result;
                         }
        diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties
        index a720cf37fff..7985449a21f 100644
        --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties
        +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties
        @@ -33,16 +33,20 @@ main.usage=Usage:\n\
         where options include:
         
         main.opt.public.desc=\
        -    Show only public classes and members
        +    Show only public types and members. For named modules,\n\
        +    show exported packages and the module''s API.
         
         main.opt.protected.desc=\
        -    Show protected/public classes and members (default)
        +    Show protected/public types and members (default). For\n\
        +    named modules, show exported packages and the module''s API.
         
         main.opt.package.desc=\
        -    Show package/protected/public classes and members
        +    Show package/protected/public types and members. For \n\
        +    named modules, show all packages and all module details.
         
         main.opt.private.desc=\
        -    Show all classes and members
        +    Show all types and members. For named modules,\n\
        +    show all packages and all module details.
         
         main.opt.show.members.arg=\
             
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java
        index c5a6cc791e8..3cc4eb02273 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java
        @@ -390,27 +390,23 @@ class ConsoleIOContext extends IOContext {
             @Override
             public boolean terminalEditorRunning() {
                 Terminal terminal = in.getTerminal();
        -        if (terminal instanceof JShellUnixTerminal)
        -            return ((JShellUnixTerminal) terminal).isRaw();
        +        if (terminal instanceof SuspendableTerminal)
        +            return ((SuspendableTerminal) terminal).isRaw();
                 return false;
             }
         
             @Override
             public void suspend() {
        -        try {
        -            in.getTerminal().restore();
        -        } catch (Exception ex) {
        -            throw new IllegalStateException(ex);
        -        }
        +        Terminal terminal = in.getTerminal();
        +        if (terminal instanceof SuspendableTerminal)
        +            ((SuspendableTerminal) terminal).suspend();
             }
         
             @Override
             public void resume() {
        -        try {
        -            in.getTerminal().init();
        -        } catch (Exception ex) {
        -            throw new IllegalStateException(ex);
        -        }
        +        Terminal terminal = in.getTerminal();
        +        if (terminal instanceof SuspendableTerminal)
        +            ((SuspendableTerminal) terminal).resume();
             }
         
             @Override
        @@ -666,7 +662,7 @@ class ConsoleIOContext extends IOContext {
                 }
             };
         
        -    private static final class JShellUnixTerminal extends NoInterruptUnixTerminal {
        +    private static final class JShellUnixTerminal extends NoInterruptUnixTerminal implements SuspendableTerminal {
         
                 private final StopDetectingInputStream input;
         
        @@ -695,9 +691,28 @@ class ConsoleIOContext extends IOContext {
                 public void enableInterruptCharacter() {
                 }
         
        +        @Override
        +        public void suspend() {
        +            try {
        +                getSettings().restore();
        +                super.disableInterruptCharacter();
        +            } catch (Exception ex) {
        +                throw new IllegalStateException(ex);
        +            }
        +        }
        +
        +        @Override
        +        public void resume() {
        +            try {
        +                init();
        +            } catch (Exception ex) {
        +                throw new IllegalStateException(ex);
        +            }
        +        }
        +
             }
         
        -    private static final class JShellWindowsTerminal extends WindowsTerminal {
        +    private static final class JShellWindowsTerminal extends WindowsTerminal implements SuspendableTerminal {
         
                 private final StopDetectingInputStream input;
         
        @@ -716,6 +731,31 @@ class ConsoleIOContext extends IOContext {
                     return input.setInputStream(super.wrapInIfNeeded(in));
                 }
         
        +        @Override
        +        public void suspend() {
        +            try {
        +                restore();
        +                setConsoleMode(getConsoleMode() & ~ConsoleMode.ENABLE_PROCESSED_INPUT.code);
        +            } catch (Exception ex) {
        +                throw new IllegalStateException(ex);
        +            }
        +        }
        +
        +        @Override
        +        public void resume() {
        +            try {
        +                restore();
        +                init();
        +            } catch (Exception ex) {
        +                throw new IllegalStateException(ex);
        +            }
        +        }
        +
        +        @Override
        +        public boolean isRaw() {
        +            return (getConsoleMode() & ConsoleMode.ENABLE_LINE_INPUT.code) == 0;
        +        }
        +
             }
         
             private static final class TestTerminal extends TerminalSupport {
        @@ -736,6 +776,12 @@ class ConsoleIOContext extends IOContext {
         
             }
         
        +    private interface SuspendableTerminal {
        +        public void suspend();
        +        public void resume();
        +        public boolean isRaw();
        +    }
        +
             private static final class CheckCompletionKeyMap extends KeyMap {
         
                 private final KeyMap del;
        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 0b6da26fc97..6cc516555fa 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
        @@ -197,7 +197,6 @@ public class JShellTool implements MessageHandler {
         
             private boolean debug = false;
             public boolean testPrompt = false;
        -    private String defaultStartup = null;
             private Startup startup = null;
             private String executionControlSpec = null;
             private EditorSetting editor = BUILT_IN_EDITOR;
        @@ -205,9 +204,9 @@ public class JShellTool implements MessageHandler {
             private static final String[] EDITOR_ENV_VARS = new String[] {
                 "JSHELLEDITOR", "VISUAL", "EDITOR"};
         
        -    // Commands and snippets which should be replayed
        -    private List replayableHistory;
        -    private List replayableHistoryPrevious;
        +    // Commands and snippets which can be replayed
        +    private ReplayableHistory replayableHistory;
        +    private ReplayableHistory replayableHistoryPrevious;
         
             static final String STARTUP_KEY  = "STARTUP";
             static final String EDITOR_KEY   = "EDITOR";
        @@ -506,6 +505,76 @@ public class JShellTool implements MessageHandler {
                 }
             }
         
        +    /**
        +     * Encapsulate a history of snippets and commands which can be replayed.
        +     */
        +    private static class ReplayableHistory {
        +
        +        // the history
        +        private List hist;
        +
        +        // the length of the history as of last save
        +        private int lastSaved;
        +
        +        private ReplayableHistory(List hist) {
        +            this.hist = hist;
        +            this.lastSaved = 0;
        +        }
        +
        +        // factory for empty histories
        +        static ReplayableHistory emptyHistory() {
        +            return new ReplayableHistory(new ArrayList<>());
        +        }
        +
        +        // factory for history stored in persistent storage
        +        static ReplayableHistory fromPrevious(PersistentStorage prefs) {
        +            // Read replay history from last jshell session
        +            String prevReplay = prefs.get(REPLAY_RESTORE_KEY);
        +            if (prevReplay == null) {
        +                return null;
        +            } else {
        +                return new ReplayableHistory(Arrays.asList(prevReplay.split(RECORD_SEPARATOR)));
        +            }
        +
        +        }
        +
        +        // store the history in persistent storage
        +        void storeHistory(PersistentStorage prefs) {
        +            if (hist.size() > lastSaved) {
        +                // Prevent history overflow by calculating what will fit, starting
        +                // with most recent
        +                int sepLen = RECORD_SEPARATOR.length();
        +                int length = 0;
        +                int first = hist.size();
        +                while (length < Preferences.MAX_VALUE_LENGTH && --first >= 0) {
        +                    length += hist.get(first).length() + sepLen;
        +                }
        +                if (first >= 0) {
        +                    hist = hist.subList(first + 1, hist.size());
        +                }
        +                String shist = String.join(RECORD_SEPARATOR, hist);
        +                prefs.put(REPLAY_RESTORE_KEY, shist);
        +                markSaved();
        +            }
        +            prefs.flush();
        +        }
        +
        +        // add a snippet or command to the history
        +        void add(String s) {
        +            hist.add(s);
        +        }
        +
        +        // return history to reloaded
        +        Iterable iterable() {
        +            return hist;
        +        }
        +
        +        // mark that persistent storage and current history are in sync
        +        void markSaved() {
        +            lastSaved = hist.size();
        +        }
        +    }
        +
             /**
              * Is the input/output currently interactive
              *
        @@ -756,10 +825,7 @@ public class JShellTool implements MessageHandler {
                 // initialize JShell instance
                 resetState();
                 // Read replay history from last jshell session into previous history
        -        String prevReplay = prefs.get(REPLAY_RESTORE_KEY);
        -        if (prevReplay != null) {
        -            replayableHistoryPrevious = Arrays.asList(prevReplay.split(RECORD_SEPARATOR));
        -        }
        +        replayableHistoryPrevious = ReplayableHistory.fromPrevious(prefs);
                 // load snippet/command files given on command-line
                 for (String loadFile : commandLineArgs.nonOptions()) {
                     runFile(loadFile, "jshell");
        @@ -775,6 +841,13 @@ public class JShellTool implements MessageHandler {
                     if (feedback.shouldDisplayCommandFluff()) {
                         hardmsg("jshell.msg.welcome", version());
                     }
        +            // Be sure history is always saved so that user code isn't lost
        +            Runtime.getRuntime().addShutdownHook(new Thread() {
        +                @Override
        +                public void run() {
        +                    replayableHistory.storeHistory(prefs);
        +                }
        +            });
                     // execute from user input
                     try (IOContext in = new ConsoleIOContext(this, cmdin, console)) {
                         start(in);
        @@ -868,7 +941,7 @@ public class JShellTool implements MessageHandler {
         
                 // Reset the replayable history, saving the old for restore
                 replayableHistoryPrevious = replayableHistory;
        -        replayableHistory = new ArrayList<>();
        +        replayableHistory = ReplayableHistory.emptyHistory();
                 JShell.Builder builder =
                        JShell.builder()
                         .in(userin)
        @@ -1933,20 +2006,7 @@ public class JShellTool implements MessageHandler {
             private boolean cmdExit() {
                 regenerateOnDeath = false;
                 live = false;
        -        if (!replayableHistory.isEmpty()) {
        -            // Prevent history overflow by calculating what will fit, starting
        -            // with most recent
        -            int sepLen = RECORD_SEPARATOR.length();
        -            int length = 0;
        -            int first = replayableHistory.size();
        -            while(length < Preferences.MAX_VALUE_LENGTH && --first >= 0) {
        -                length += replayableHistory.get(first).length() + sepLen;
        -            }
        -            String hist =  String.join(RECORD_SEPARATOR,
        -                    replayableHistory.subList(first + 1, replayableHistory.size()));
        -            prefs.put(REPLAY_RESTORE_KEY, hist);
        -        }
        -        prefs.flush();
        +        replayableHistory.storeHistory(prefs);
                 fluffmsg("jshell.msg.goodbye");
                 return true;
             }
        @@ -2420,7 +2480,7 @@ public class JShellTool implements MessageHandler {
                 if (!parseCommandLineLikeFlags(rawargs, ap)) {
                     return false;
                 }
        -        Iterable history;
        +        ReplayableHistory history;
                 if (ap.restore()) {
                     if (replayableHistoryPrevious == null) {
                         errormsg("jshell.err.reload.no.previous");
        @@ -2432,7 +2492,13 @@ public class JShellTool implements MessageHandler {
                     history = replayableHistory;
                     fluffmsg("jshell.err.reload.restarting.state");
                 }
        -        return doReload(history, !ap.quiet());
        +        boolean success = doReload(history, !ap.quiet());
        +        if (success && ap.restore()) {
        +            // if we are restoring from previous, then if nothing was added
        +            // before time of exit, there is nothing to save
        +            replayableHistory.markSaved();
        +        }
        +        return success;
             }
         
             private boolean cmdEnv(String rawargs) {
        @@ -2460,9 +2526,9 @@ public class JShellTool implements MessageHandler {
                 return doReload(replayableHistory, false);
             }
         
        -    private boolean doReload(Iterable history, boolean echo) {
        +    private boolean doReload(ReplayableHistory history, boolean echo) {
                 resetState();
        -        run(new ReloadIOContext(history,
        +        run(new ReloadIOContext(history.iterable(),
                         echo ? cmdout : null));
                 return true;
             }
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java
        index 10c5d0468e8..ee3079f560e 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java
        @@ -85,7 +85,7 @@ class CompletenessAnalyzer {
                 try {
                     Parser parser = new Parser(
                             () -> new Matched(scannerFactory.newScanner(s, false)),
        -                    () -> proc.taskFactory.new ParseTask(s));
        +                    () -> proc.taskFactory.parse(s));
                     Completeness stat = parser.parseUnit();
                     int endPos = stat == Completeness.UNKNOWN
                             ? s.length()
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
        index de259506ac4..fcb47252726 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
        @@ -155,7 +155,7 @@ class Eval {
                 if (compileSource.length() == 0) {
                     return Collections.emptyList();
                 }
        -        ParseTask pt = state.taskFactory.new ParseTask(compileSource);
        +        ParseTask pt = state.taskFactory.parse(compileSource);
                 List units = pt.units();
                 if (units.isEmpty()) {
                     return compileFailResult(pt, userSource, Kind.ERRONEOUS);
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java
        index 96252cf856c..1d98f6ad3b7 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -39,7 +39,6 @@ import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
         import static com.sun.tools.javac.parser.Tokens.TokenKind.INTERFACE;
         import static com.sun.tools.javac.parser.Tokens.TokenKind.LPAREN;
         import static com.sun.tools.javac.parser.Tokens.TokenKind.MONKEYS_AT;
        -import static com.sun.tools.javac.parser.Tokens.TokenKind.PACKAGE;
         import static com.sun.tools.javac.parser.Tokens.TokenKind.SEMI;
         import static com.sun.tools.javac.parser.Tokens.TokenKind.VOID;
         import com.sun.tools.javac.tree.JCTree;
        @@ -48,10 +47,8 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
         import com.sun.tools.javac.tree.JCTree.JCExpression;
         import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
         import com.sun.tools.javac.tree.JCTree.JCModifiers;
        -import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
         import com.sun.tools.javac.tree.JCTree.JCStatement;
         import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
        -import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
         import com.sun.tools.javac.tree.JCTree.Tag;
         import static com.sun.tools.javac.tree.JCTree.Tag.IDENT;
         import com.sun.tools.javac.util.List;
        @@ -68,12 +65,17 @@ import com.sun.tools.javac.util.Position;
          */
         class ReplParser extends JavacParser {
         
        +    // force starting in expression mode
        +    private final boolean forceExpression;
        +
             public ReplParser(ParserFactory fac,
                     com.sun.tools.javac.parser.Lexer S,
                     boolean keepDocComments,
                     boolean keepLineMap,
        -            boolean keepEndPositions) {
        +            boolean keepEndPositions,
        +            boolean forceExpression) {
                 super(fac, S, keepDocComments, keepLineMap, keepEndPositions);
        +        this.forceExpression = forceExpression;
             }
         
             /**
        @@ -205,7 +207,10 @@ class ReplParser extends JavacParser {
                                 nextToken();
                             } else {
                                 // return type of method, declared type of variable, or an expression
        -                        t = term(EXPR | TYPE);
        +                        // unless expression is being forced
        +                        t = term(forceExpression
        +                                ? EXPR
        +                                : EXPR | TYPE);
                             }
                             if (token.kind == COLON && t.hasTag(IDENT)) {
                                 // labelled statement
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java
        index 018d39153d6..604bfe71070 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParserFactory.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -36,24 +36,30 @@ import com.sun.tools.javac.util.Context;
          */
         class ReplParserFactory extends ParserFactory {
         
        -    public static ParserFactory instance(Context context) {
        -        ParserFactory instance = context.get(parserFactoryKey);
        -        if (instance == null) {
        -            instance = new ReplParserFactory(context);
        -        }
        -        return instance;
        +    // force starting in expression mode
        +    private final boolean forceExpression;
        +
        +    public static void preRegister(Context context, boolean forceExpression) {
        +        context.put(parserFactoryKey, (Context.Factory)
        +                (c -> new ReplParserFactory(c, forceExpression)));
             }
         
             private final ScannerFactory scannerFactory;
         
        -    protected ReplParserFactory(Context context) {
        +    protected ReplParserFactory(Context context, boolean forceExpression) {
                 super(context);
        +        this.forceExpression = forceExpression;
                 this.scannerFactory = ScannerFactory.instance(context);
             }
         
             @Override
             public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap) {
                 com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments);
        -        return new ReplParser(this, lexer, keepDocComments, keepLineMap, keepEndPos);
        +        return new ReplParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, forceExpression);
        +    }
        +
        +    @Override
        +    public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) {
        +        return newParser(input, keepDocComments, keepEndPos, keepLineMap);
             }
         }
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
        index 2ebc424b151..93128144708 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
        @@ -227,7 +227,7 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
             }
         
             private Tree.Kind guessKind(String code) {
        -        ParseTask pt = proc.taskFactory.new ParseTask(code);
        +        ParseTask pt = proc.taskFactory.parse(code);
                 List units = pt.units();
                 if (units.isEmpty()) {
                     return Tree.Kind.BLOCK;
        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 6b2d441eb74..53ed54c73e6 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -61,6 +61,7 @@ import javax.lang.model.util.Elements;
         import javax.tools.FileObject;
         import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
         import java.lang.Runtime.Version;
        +import com.sun.source.tree.Tree.Kind;
         
         /**
          * The primary interface to the compiler API.  Parsing, analysis, and
        @@ -100,6 +101,23 @@ class TaskFactory {
                 return fileManager;
             }
         
        +    // Parse a snippet and return our parse task handler
        +    ParseTask parse(final String source) {
        +        ParseTask pt = state.taskFactory.new ParseTask(source, false);
        +        if (!pt.units().isEmpty()
        +                && pt.units().get(0).getKind() == Kind.EXPRESSION_STATEMENT
        +                && pt.getDiagnostics().hasOtherThanNotStatementErrors()) {
        +            // It failed, it may be an expression being incorrectly
        +            // parsed as having a leading type variable, example:   a < b
        +            // Try forcing interpretation as an expression
        +            ParseTask ept = state.taskFactory.new ParseTask(source, true);
        +            if (!ept.getDiagnostics().hasOtherThanNotStatementErrors()) {
        +                return ept;
        +            }
        +        }
        +        return pt;
        +    }
        +
             private interface SourceHandler {
         
                 JavaFileObject sourceToFileObject(MemoryFileManager fm, T t);
        @@ -179,11 +197,11 @@ class TaskFactory {
                 private final Iterable cuts;
                 private final List units;
         
        -        ParseTask(final String source) {
        +        ParseTask(final String source, final boolean forceExpression) {
                     super(Stream.of(source),
                             new StringSourceHandler(),
                             "-XDallowStringFolding=false", "-proc:none");
        -            ReplParserFactory.instance(getContext());
        +            ReplParserFactory.preRegister(getContext(), forceExpression);
                     cuts = parse();
                     units = Util.stream(cuts)
                             .flatMap(cut -> {
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java
        index 4ac77ee4d35..d40e10a59a1 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/DirectExecutionControl.java
        @@ -28,6 +28,7 @@ import java.lang.reflect.Array;
         import java.lang.reflect.Field;
         import java.lang.reflect.InvocationTargetException;
         import java.lang.reflect.Method;
        +import java.util.stream.IntStream;
         import jdk.jshell.spi.ExecutionControl;
         import jdk.jshell.spi.SPIResolutionException;
         
        @@ -41,6 +42,23 @@ import jdk.jshell.spi.SPIResolutionException;
          */
         public class DirectExecutionControl implements ExecutionControl {
         
        +    private static final String[] charRep;
        +
        +    static {
        +        charRep = new String[256];
        +        for (int i = 0; i < charRep.length; ++i) {
        +            charRep[i] = Character.isISOControl(i)
        +                    ? String.format("\\%03o", i)
        +                    : "" + (char) i;
        +        }
        +        charRep['\b'] = "\\b";
        +        charRep['\t'] = "\\t";
        +        charRep['\n'] = "\\n";
        +        charRep['\f'] = "\\f";
        +        charRep['\r'] = "\\r";
        +        charRep['\\'] = "\\\\";
        +    }
        +
             private final LoaderDelegate loaderDelegate;
         
             /**
        @@ -192,9 +210,26 @@ public class DirectExecutionControl implements ExecutionControl {
                 if (value == null) {
                     return "null";
                 } else if (value instanceof String) {
        -            return "\"" + (String) value + "\"";
        +            return "\"" + ((String) value).codePoints()
        +                    .flatMap(cp ->
        +                        (cp == '"')
        +                            ? "\\\"".codePoints()
        +                            : (cp < 256)
        +                                ? charRep[cp].codePoints()
        +                                : IntStream.of(cp))
        +                    .collect(
        +                            StringBuilder::new,
        +                            StringBuilder::appendCodePoint,
        +                            StringBuilder::append)
        +                    .toString() + "\"";
                 } else if (value instanceof Character) {
        -            return "'" + value + "'";
        +            char cp = (char) (Character) value;
        +            return "'" + (
        +                (cp == '\'')
        +                    ? "\\\'"
        +                    : (cp < 256)
        +                            ? charRep[cp]
        +                            : String.valueOf(cp)) + "'";
                 } else if (value.getClass().isArray()) {
                     int dims = 0;
                     Class t = value.getClass();
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/FailOverExecutionControlProvider.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/FailOverExecutionControlProvider.java
        index ba339640284..4894efc7b1b 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/FailOverExecutionControlProvider.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/FailOverExecutionControlProvider.java
        @@ -111,7 +111,8 @@ public class FailOverExecutionControlProvider  implements ExecutionControlProvid
                             PrintWriter log = new PrintWriter(writer);
                             log.println("FailOverExecutionControlProvider:");
                             ex.printStackTrace(log);
        -                    logger().fine(log.toString());
        +                    log.flush();
        +                    logger().fine(writer.toString());
                             // only care about the first, and only if they all fail
                             if (thrown == null) {
                                 thrown = ex;
        diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java
        index b989c42b7d1..bce34fe1179 100644
        --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java
        +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/execution/JdiDefaultExecutionControl.java
        @@ -102,7 +102,6 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
                     Process process = jdii.process();
         
                     List> deathListeners = new ArrayList<>();
        -            deathListeners.add(s -> env.closeDown());
                     Util.detectJdiExitEvent(vm, s -> {
                         for (Consumer h : deathListeners) {
                             h.accept(s);
        @@ -120,7 +119,8 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
                     Map input = new HashMap<>();
                     input.put("in", env.userIn());
                     return remoteInputOutput(socket.getInputStream(), out, outputs, input,
        -                    (objIn, objOut) -> new JdiDefaultExecutionControl(objOut, objIn, vm, process, remoteAgent, deathListeners));
        +                    (objIn, objOut) -> new JdiDefaultExecutionControl(env,
        +                                        objOut, objIn, vm, process, remoteAgent, deathListeners));
                 }
             }
         
        @@ -130,15 +130,20 @@ public class JdiDefaultExecutionControl extends JdiExecutionControl {
              * @param cmdout the output for commands
              * @param cmdin the input for responses
              */
        -    private JdiDefaultExecutionControl(ObjectOutput cmdout, ObjectInput cmdin,
        +    private JdiDefaultExecutionControl(ExecutionEnv env,
        +            ObjectOutput cmdout, ObjectInput cmdin,
                     VirtualMachine vm, Process process, String remoteAgent,
                     List> deathListeners) {
                 super(cmdout, cmdin);
                 this.vm = vm;
                 this.process = process;
                 this.remoteAgent = remoteAgent;
        +        // We have now succeeded in establishing the connection.
        +        // If there is an exit now it propagates all the way up
        +        // and the VM should be disposed of.
        +        deathListeners.add(s -> env.closeDown());
                 deathListeners.add(s -> disposeVM());
        -    }
        +     }
         
             @Override
             public String invoke(String classname, String methodname)
        diff --git a/langtools/src/jdk.jshell/share/classes/module-info.java b/langtools/src/jdk.jshell/share/classes/module-info.java
        index ed0ecd49b52..6c8311292a1 100644
        --- a/langtools/src/jdk.jshell/share/classes/module-info.java
        +++ b/langtools/src/jdk.jshell/share/classes/module-info.java
        @@ -1,5 +1,5 @@
         /*
        - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
        + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
          * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
          *
          * This code is free software; you can redistribute it and/or modify it
        @@ -70,11 +70,10 @@ module jdk.jshell {
             uses jdk.jshell.spi.ExecutionControlProvider;
             uses jdk.internal.editor.spi.BuildInEditorProvider;
         
        -    provides javax.tools.Tool with jdk.internal.jshell.tool.JShellToolProvider;
        +    provides javax.tools.Tool
        +        with jdk.internal.jshell.tool.JShellToolProvider;
             provides jdk.jshell.spi.ExecutionControlProvider
        -        with jdk.jshell.execution.JdiExecutionControlProvider;
        -    provides jdk.jshell.spi.ExecutionControlProvider
        -        with jdk.jshell.execution.LocalExecutionControlProvider;
        -    provides jdk.jshell.spi.ExecutionControlProvider
        -        with jdk.jshell.execution.FailOverExecutionControlProvider;
        +        with jdk.jshell.execution.JdiExecutionControlProvider,
        +             jdk.jshell.execution.LocalExecutionControlProvider,
        +             jdk.jshell.execution.FailOverExecutionControlProvider;
         }
        diff --git a/langtools/test/com/sun/javadoc/testNonInlineHtmlTagRemoval/C.java b/langtools/test/com/sun/javadoc/testNonInlineHtmlTagRemoval/C.java
        new file mode 100644
        index 00000000000..09b8a237794
        --- /dev/null
        +++ b/langtools/test/com/sun/javadoc/testNonInlineHtmlTagRemoval/C.java
        @@ -0,0 +1,74 @@
        +/*
        + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
        + * 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.
        + */
        +
        +public class C {
        +    /**
        +     * case1 
        • end of sentence.
        • more
        + */ + public void case1() {} + + /** + * case2
        • end of sentence.
        • more
        + */ + public void case2() {} + + /** + * case3
        • end of sentence.
        • more
        + */ + public void case3() {} + + /** + * case4
        • end of sentence.
        • more
        + */ + public void case4() {} + + /** + * case5
        • end of sentence.
        • more
        + */ + public void case5() {} + + /** + * case6
        • end of sentence.
        • more
        + */ + public void case6() {} + + /** + * case7
        • end of sentence.
        • more
        + */ + public void case7() {} + + /** + * case8
        • end of sentence.
        • more
        + */ + public void case8() {} + + /** + * case9
        • end of sentence.
        • more
        + */ + public void case9() {} + + /** + * caseA
        • end of sentence.
        • more
        + */ + public void caseA() {} +} diff --git a/langtools/test/com/sun/javadoc/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java b/langtools/test/com/sun/javadoc/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java new file mode 100644 index 00000000000..ba371521442 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8048628 + * @summary Verify html inline tags are removed correctly in the first sentence. + * @library ../lib + * @modules jdk.javadoc + * @build JavadocTester + * @run main TestNonInlineHtmlTagRemoval + */ + +public class TestNonInlineHtmlTagRemoval extends JavadocTester { + + public static void main(String... args) throws Exception { + TestNonInlineHtmlTagRemoval tester = new TestNonInlineHtmlTagRemoval(); + tester.runTests(); + } + + @Test + void test() { + javadoc("-d", "out", + "-sourcepath", testSrc, + testSrc("C.java")); + checkExit(Exit.OK); + + checkOutput("C.html", true, + "
        case1 end of sentence.
        ", + "
        case2 end of sentence.
        ", + "
        case3 end of sentence.
        ", + "
        case4 end of sentence.
        ", + "
        case5 end of sentence.
        ", + "
        case6 end of sentence.
        ", + "
        case7 end of sentence.
        ", + "
        case8 end of sentence.
        ", + "
        case9 end of sentence.
        ", + "
        caseA end of sentence.
        "); + } +} diff --git a/langtools/test/jdk/javadoc/doclet/testFramesNoFrames/TestFramesNoFrames.java b/langtools/test/jdk/javadoc/doclet/testFramesNoFrames/TestFramesNoFrames.java index bb3fee6849e..31a307ba445 100644 --- a/langtools/test/jdk/javadoc/doclet/testFramesNoFrames/TestFramesNoFrames.java +++ b/langtools/test/jdk/javadoc/doclet/testFramesNoFrames/TestFramesNoFrames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +23,7 @@ /* * @test - * @bug 8162353 8164747 + * @bug 8162353 8164747 8173707 * @summary javadoc should provide a way to disable use of frames * @library /tools/lib ../lib * @modules @@ -323,10 +323,14 @@ public class TestFramesNoFrames extends JavadocTester { } private void checkIndex() { - // the index.html page only contains frames in frames mode + // the index.html page only contains frames and Javascript to default to no-frames view, + // in frames mode checkOutput("index.html", frames, "", + "\n" + + "\n" + + "\n" + "
        \n" + "
        \n" + "
        \n" @@ -1012,6 +1017,11 @@ public class TestHtmlVersion extends JavadocTester { checkOutput("index.html", false, "", "\n" + + "\n" + + "\n" + "
        \n"); } @@ -1424,6 +1434,11 @@ public class TestHtmlVersion extends JavadocTester { "", "", "\n" + + "\n" + + "\n" + "
        \n" + "
        \n" + "
        \n" @@ -1924,6 +1939,11 @@ public class TestHtmlVersion extends JavadocTester { checkOutput("index.html", false, "", "\n" + + "\n" + + "\n" + "
        \n" + "
        \n"); } diff --git a/langtools/test/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java b/langtools/test/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java index bb9c951876b..c666c3384b6 100644 --- a/langtools/test/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java +++ b/langtools/test/jdk/javadoc/doclet/testJavaFX/TestJavaFX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +23,7 @@ /* * @test - * @bug 7112427 8012295 8025633 8026567 8061305 8081854 8150130 8162363 8167967 + * @bug 7112427 8012295 8025633 8026567 8061305 8081854 8150130 8162363 8167967 8172528 * @summary Test of the JavaFX doclet features. * @author jvalenta * @library ../lib @@ -50,93 +50,103 @@ public class TestJavaFX extends JavadocTester { checkOutput("pkg1/C.html", true, "
        See Also:
        \n" - + "
        getRate(), \n" - + "" - + "setRate(double)
        ", + + "
        getRate(), \n" + + "" + + "setRate(double)
        ", "
        public final void setRate(double value)
        \n" - + "
        Sets the value of the property rate.
        \n" - + "
        \n" - + "
        Property description:
        ", + + "
        Sets the value of the property rate.
        \n" + + "
        \n" + + "
        Property description:
        ", "
        public final double getRate()
        \n" - + "
        Gets the value of the property rate.
        \n" - + "
        \n" - + "
        Property description:
        ", + + "
        Gets the value of the property rate.
        \n" + + "
        \n" + + "
        Property description:
        ", "C.DoubleProperty\n" - + "" - + "rate\n" - + "\n" - + "
        Defines the direction/speed at which the " - + "Timeline is expected to\n" - + " be played.
        \n", + + "title=\"class in pkg1\">C.DoubleProperty\n" + + "" + + "rate\n" + + "\n" + + "
        Defines the direction/speed at which the " + + "Timeline is expected to\n" + + " be played.
        \n", "Default value:", "Since:\n" - + "
        JavaFX 8.0
        ", + + "
        JavaFX 8.0
        ", "

        Sets the value of the property Property", "

        Gets the value of the property Property", "Property description:", "" - + "" - + "setTestMethodProperty()", + + "" + + "setTestMethodProperty()", "" - + "paused\n" - + "\n" - + "

        Defines if paused.
        ", + + "paused\n" + + "\n" + + "
        Defines if paused.
        ", "

        paused

        \n" - + "
        public final C.BooleanProperty pausedProperty
        \n" - + "
        Defines if paused. The second line.
        ", + + "
        public final C.BooleanProperty pausedProperty
        \n" + + "
        Defines if paused. The second line.
        ", "

        isPaused

        \n" - + "
        public final double isPaused()
        \n" - + "
        Gets the value of the property paused.
        ", + + "
        public final double isPaused()
        \n" + + "
        Gets the value of the property paused.
        ", "

        setPaused

        \n" - + "
        public final void setPaused(boolean value)
        \n" - + "
        Sets the value of the property paused.
        \n" - + "
        \n" - + "
        Property description:
        \n" - + "
        Defines if paused. The second line.
        \n" - + "
        Default value:
        \n" - + "
        false
        ", + + "
        public final void setPaused(boolean value)
        \n" + + "
        Sets the value of the property paused.
        \n" + + "
        \n" + + "
        Property description:
        \n" + + "
        Defines if paused. The second line.
        \n" + + "
        Default value:
        \n" + + "
        false
        ", "

        isPaused

        \n" - + "
        public final double isPaused()
        \n" - + "
        Gets the value of the property paused.
        \n" - + "
        \n" - + "
        Property description:
        \n" - + "
        Defines if paused. The second line.
        \n" - + "
        Default value:
        \n" - + "
        false
        ", + + "
        public final double isPaused()
        \n" + + "
        Gets the value of the property paused.
        \n" + + "
        \n" + + "
        Property description:
        \n" + + "
        Defines if paused. The second line.
        \n" + + "
        Default value:
        \n" + + "
        false
        ", "

        rate

        \n" - + "
        public final C.DoubleProperty rateProperty
        \n" - + "
        Defines the direction/speed at which the " - + "Timeline is expected to\n" - + " be played. This is the second line.
        ", + + "
        public final C.DoubleProperty rateProperty
        \n" + + "
        Defines the direction/speed at which the " + + "Timeline is expected to\n" + + " be played. This is the second line.
        ", "

        setRate

        \n" - + "
        public final void setRate(double value)
        \n" - + "
        Sets the value of the property rate.
        \n" - + "
        \n" - + "
        Property description:
        \n" - + "
        Defines the direction/speed at which the Timeline is expected to\n" - + " be played. This is the second line.
        \n" - + "
        Default value:
        \n" - + "
        11
        \n" - + "
        Since:
        \n" - + "
        JavaFX 8.0
        ", + + "
        public final void setRate(double value)
        \n" + + "
        Sets the value of the property rate.
        \n" + + "
        \n" + + "
        Property description:
        \n" + + "
        Defines the direction/speed at which the Timeline is expected to\n" + + " be played. This is the second line.
        \n" + + "
        Default value:
        \n" + + "
        11
        \n" + + "
        Since:
        \n" + + "
        JavaFX 8.0
        ", "

        getRate

        \n" - + "
        public final double getRate()
        \n" - + "
        Gets the value of the property rate.
        \n" - + "
        \n" - + "
        Property description:
        \n" - + "
        Defines the direction/speed at which the Timeline is expected to\n" - + " be played. This is the second line.
        \n" - + "
        Default value:
        \n" - + "
        11
        \n" - + "
        Since:
        \n" - + "
        JavaFX 8.0
        ", + + "
        public final double getRate()
        \n" + + "
        Gets the value of the property rate.
        \n" + + "
        \n" + + "
        Property description:
        \n" + + "
        Defines the direction/speed at which the Timeline is expected to\n" + + " be played. This is the second line.
        \n" + + "
        Default value:
        \n" + + "
        11
        \n" + + "
        Since:
        \n" + + "
        JavaFX 8.0
        ", + "

        Property Summary

        \n" + + "\n" + + "", ""); checkOutput("pkg1/C.html", false, - "A()"); + "A()", + "

        Property Summary

        \n" + + "
        Properties 
        \n" + + ""); checkOutput("index-all.html", true, "
        Gets the value of the property paused.
        ", @@ -193,7 +203,19 @@ public class TestJavaFX extends JavadocTester { + "\n" + "\n" + "\n" - + ""); + + "", + "

        Property Summary

        \n" + + "
        All Methods " + + "Instance Methods" + + " " + + "Concrete Methods " + + "
        \n" + + ""); + + checkOutput("pkg2/Test.html", false, + "

        Property Summary

        \n" + + "
        Properties 
        \n" + + ""); } /* diff --git a/langtools/test/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/C.java b/langtools/test/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/C.java new file mode 100644 index 00000000000..09b8a237794 --- /dev/null +++ b/langtools/test/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/C.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +public class C { + /** + * case1
        • end of sentence.
        • more
        + */ + public void case1() {} + + /** + * case2
        • end of sentence.
        • more
        + */ + public void case2() {} + + /** + * case3
        • end of sentence.
        • more
        + */ + public void case3() {} + + /** + * case4
        • end of sentence.
        • more
        + */ + public void case4() {} + + /** + * case5
        • end of sentence.
        • more
        + */ + public void case5() {} + + /** + * case6
        • end of sentence.
        • more
        + */ + public void case6() {} + + /** + * case7
        • end of sentence.
        • more
        + */ + public void case7() {} + + /** + * case8
        • end of sentence.
        • more
        + */ + public void case8() {} + + /** + * case9
        • end of sentence.
        • more
        + */ + public void case9() {} + + /** + * caseA
        • end of sentence.
        • more
        + */ + public void caseA() {} +} diff --git a/langtools/test/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java b/langtools/test/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java new file mode 100644 index 00000000000..f1f85b51b0e --- /dev/null +++ b/langtools/test/jdk/javadoc/doclet/testNonInlineHtmlTagRemoval/TestNonInlineHtmlTagRemoval.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8048628 + * @summary Verify html inline tags are removed correctly in the first sentence. + * @library ../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build JavadocTester + * @run main TestNonInlineHtmlTagRemoval + */ + +public class TestNonInlineHtmlTagRemoval extends JavadocTester { + + public static void main(String... args) throws Exception { + TestNonInlineHtmlTagRemoval tester = new TestNonInlineHtmlTagRemoval(); + tester.runTests(); + } + + @Test + void test() { + javadoc("-d", "out", + "-sourcepath", testSrc, + testSrc("C.java")); + checkExit(Exit.OK); + + checkOutput("C.html", true, + "
        case1 end of sentence.
        ", + "
        case2 end of sentence.
        ", + "
        case3 end of sentence.
        ", + "
        case4 end of sentence.
        ", + "
        case5 end of sentence.
        ", + "
        case6 end of sentence.
        ", + "
        case7 end of sentence.
        ", + "
        case8 end of sentence.
        ", + "
        case9 end of sentence.
        ", + "
        caseA end of sentence.
        "); + } +} diff --git a/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java b/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java index 19626d84d10..9222f73d73a 100644 --- a/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java +++ b/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +23,7 @@ /* * @test - * @bug 8039410 8042601 8042829 8049393 8050031 8155061 8155995 8167967 + * @bug 8039410 8042601 8042829 8049393 8050031 8155061 8155995 8167967 8169813 * @summary test to determine if members are ordered correctly * @library ../lib/ * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -494,23 +494,23 @@ public class TestOrdering extends JavadocTester { String[] composeTestVectors() { List testList = new ArrayList<>(); - testList.addAll(Arrays.asList(expectedPackageOrdering)); for (String x : expectedEnumOrdering) { testList.add(x.replace("REPLACE_ME", "<Unnamed>")); - for (int i = 0; i < MAX_PACKAGES; i++) { - String wpkg = "add" + i; - testList.add(wpkg + "/" + x.replace("REPLACE_ME", - wpkg)); - String dpkg = wpkg; - for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) { - dpkg = dpkg + "/" + "add"; + } + for (int i = 0; i < MAX_PACKAGES; i++) { + String wpkg = "add" + i; + for (String x : expectedEnumOrdering) { + testList.add(wpkg + "/" + x.replace("REPLACE_ME", wpkg)); + } + String dpkg = wpkg; + for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) { + dpkg = dpkg + "/" + "add"; + for (String x : expectedEnumOrdering) { testList.add(dpkg + "/" + x.replace("REPLACE_ME", pathToPackage(dpkg))); } } } - testList.addAll(Arrays.asList(expectedFieldOrdering)); - for (String x : expectedMethodOrdering) { testList.add(x); for (int i = 0; i < MAX_PACKAGES; i++) { @@ -523,6 +523,8 @@ public class TestOrdering extends JavadocTester { } } } + testList.addAll(Arrays.asList(expectedPackageOrdering)); + testList.addAll(Arrays.asList(expectedFieldOrdering)); return testList.toArray(new String[testList.size()]); } diff --git a/langtools/test/jdk/jshell/ExecutionControlTestBase.java b/langtools/test/jdk/jshell/ExecutionControlTestBase.java index 6e066227122..6bf5a55fb72 100644 --- a/langtools/test/jdk/jshell/ExecutionControlTestBase.java +++ b/langtools/test/jdk/jshell/ExecutionControlTestBase.java @@ -23,6 +23,7 @@ import javax.tools.Diagnostic; +import org.testng.annotations.Test; import jdk.jshell.VarSnippet; import static jdk.jshell.Snippet.Status.VALID; @@ -30,6 +31,7 @@ import static jdk.jshell.Snippet.SubKind.*; public class ExecutionControlTestBase extends KullaTesting { + @Test public void classesDeclaration() { assertEval("interface A { }"); assertEval("class B implements A { }"); @@ -45,6 +47,7 @@ public class ExecutionControlTestBase extends KullaTesting { assertActiveKeys(); } + @Test public void interfaceTest() { String interfaceSource = "interface A {\n" @@ -72,6 +75,7 @@ public class ExecutionControlTestBase extends KullaTesting { assertEval("new B.Inner2();"); } + @Test public void variables() { VarSnippet snx = varKey(assertEval("int x = 10;")); VarSnippet sny = varKey(assertEval("String y = \"hi\";")); @@ -83,6 +87,7 @@ public class ExecutionControlTestBase extends KullaTesting { assertActiveKeys(); } + @Test public void methodOverload() { assertEval("int m() { return 1; }"); assertEval("int m(int x) { return 2; }"); @@ -107,6 +112,7 @@ public class ExecutionControlTestBase extends KullaTesting { assertActiveKeys(); } + @Test public void testExprSanity() { assertEval("int x = 3;", "3"); assertEval("int y = 4;", "4"); @@ -114,6 +120,7 @@ public class ExecutionControlTestBase extends KullaTesting { assertActiveKeys(); } + @Test public void testImportOnDemand() { assertImportKeyMatch("import java.util.*;", "java.util.*", TYPE_IMPORT_ON_DEMAND_SUBKIND, added(VALID)); assertEval("List list = new ArrayList<>();"); diff --git a/langtools/test/jdk/jshell/FailOverDirectExecutionControlTest.java b/langtools/test/jdk/jshell/FailOverDirectExecutionControlTest.java index 5e07d6bcd3a..918af79c91b 100644 --- a/langtools/test/jdk/jshell/FailOverDirectExecutionControlTest.java +++ b/langtools/test/jdk/jshell/FailOverDirectExecutionControlTest.java @@ -61,7 +61,8 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase ClassLoader ccl; ExecutionControlProvider provider; - Map> logged = new HashMap<>(); + LogTestHandler hndlr; + Map> logged; private class LogTestHandler extends Handler { @@ -95,7 +96,9 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase public void setUp() { Logger logger = Logger.getLogger("jdk.jshell.execution"); logger.setLevel(Level.ALL); - logger.addHandler(new LogTestHandler()); + hndlr = new LogTestHandler(); + logger.addHandler(hndlr); + logged = new HashMap<>(); Compiler compiler = new Compiler(); Path modDir = Paths.get("mod"); compiler.compile(modDir, @@ -133,6 +136,8 @@ public class FailOverDirectExecutionControlTest extends ExecutionControlTestBase @Override public void tearDown() { super.tearDown(); + Logger logger = Logger.getLogger("jdk.jshell.execution"); + logger.removeHandler(hndlr); Thread.currentThread().setContextClassLoader(ccl); } diff --git a/langtools/test/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java b/langtools/test/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java index a08343c6fc7..e838252f540 100644 --- a/langtools/test/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java +++ b/langtools/test/jdk/jshell/FailOverExecutionControlDyingLaunchTest.java @@ -27,7 +27,7 @@ * @summary Test that fail-over works for fail-over ExecutionControl generators. * @modules jdk.jshell/jdk.jshell.execution * jdk.jshell/jdk.jshell.spi - * @build KullaTesting ExecutionControlTestBase + * @build KullaTesting ExecutionControlTestBase DyingRemoteAgent * @run testng FailOverExecutionControlDyingLaunchTest */ diff --git a/langtools/test/jdk/jshell/SimpleRegressionTest.java b/langtools/test/jdk/jshell/SimpleRegressionTest.java index a3efe9c6750..3a658e04400 100644 --- a/langtools/test/jdk/jshell/SimpleRegressionTest.java +++ b/langtools/test/jdk/jshell/SimpleRegressionTest.java @@ -22,7 +22,7 @@ */ /* - * @test 8130450 8158906 8154374 8166400 8171892 + * @test 8130450 8158906 8154374 8166400 8171892 8173807 8173848 * @summary simple regression test * @build KullaTesting TestingInputStream * @run testng SimpleRegressionTest @@ -76,6 +76,15 @@ public class SimpleRegressionTest extends KullaTesting { assertEval("c;", "600"); } + public void testLessThanParsing() { + assertEval("int x = 3;", "3"); + assertEval("int y = 4;", "4"); + assertEval("int z = 5;", "5"); + assertEval("x < y", "true"); + assertEval("x < y;", "true"); + assertEval("x < y && y < z", "true"); + } + public void testNotStmtCannotResolve() { assertDeclareFail("dfasder;", new ExpectedDiagnostic("compiler.err.cant.resolve.location", 0, 7, 0, -1, -1, Diagnostic.Kind.ERROR)); } @@ -182,4 +191,36 @@ public class SimpleRegressionTest extends KullaTesting { assertEval("new boolean[2][1][3]", "boolean[2][][] { boolean[1][] { boolean[3] { false, false, false } }, boolean[1][] { boolean[3] { false, false, false } } }"); } + + public void testStringRepresentation() { + assertEval("\"A!\\rB!\"", + "\"A!\\rB!\""); + assertEval("\"a\\bB\\tc\\nd\\fe\\rf\\\"g'\\\\h\"", + "\"a\\bB\\tc\\nd\\fe\\rf\\\"g'\\\\h\""); + assertEval("\"\\141\\10B\\11c\\nd\\fe\\15f\\42g\\'\\134h\"", + "\"a\\bB\\tc\\nd\\fe\\rf\\\"g'\\\\h\""); + assertEval("\"1234567890!@#$%^&*()-_=+qwertQWERT,./<>?;:[]{}\"", + "\"1234567890!@#$%^&*()-_=+qwertQWERT,./<>?;:[]{}\""); + assertEval("\"AA\\1\\7\\35\\25\"", + "\"AA\\001\\007\\035\\025\""); + assertEval("\"\"", + "\"\""); + assertEval("(String)null", + "null"); + } + + public void testCharRepresentation() { + for (String s : new String[]{"'A'", "'Z'", "'0'", "'9'", + "'a'", "'z'", "'*'", "'%'", + "'\\b'", "'\\t'", "'\\n'", "'\\f'", "'\\r'", + "'\"'", "'\\\''", "'\\\\'", "'\\007'", "'\\034'",}) { + assertEval(s, s); + } + assertEval("'\\3'", + "'\\003'"); + assertEval("'\\u001D'", + "'\\035'"); + assertEval("\"a\\bb\\tc\\nd\\fe\\rf\\\"g'\\\\h\".charAt(1)", + "'\\b'"); + } } diff --git a/langtools/test/jdk/jshell/ToolSimpleTest.java b/langtools/test/jdk/jshell/ToolSimpleTest.java index 75e329ec047..ff29a47a92f 100644 --- a/langtools/test/jdk/jshell/ToolSimpleTest.java +++ b/langtools/test/jdk/jshell/ToolSimpleTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 + * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 * @summary Simple jshell tool tests * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -73,6 +73,18 @@ public class ToolSimpleTest extends ReplToolTesting { ); } + @Test + public void testLessThan() { + test( + (a) -> assertCommand(a, "45", "$1 ==> 45"), + (a) -> assertCommand(a, "72", "$2 ==> 72"), + (a) -> assertCommand(a, "$1 < $2", "$3 ==> true"), + (a) -> assertCommand(a, "int a, b", "a ==> 0\n" + + "b ==> 0"), + (a) -> assertCommand(a, "a < b", "$6 ==> false") + ); + } + @Test public void oneLineOfError() { test( diff --git a/langtools/test/tools/javac/diags/examples/DuplicateProvides/module-info.java b/langtools/test/tools/javac/diags/examples/DuplicateProvides/module-info.java index d8e2916f86d..b628691c11f 100644 --- a/langtools/test/tools/javac/diags/examples/DuplicateProvides/module-info.java +++ b/langtools/test/tools/javac/diags/examples/DuplicateProvides/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,6 @@ module DuplicateExports { exports exported; - provides exported.Service with impl.ServiceImplementation; - provides exported.Service with impl.ServiceImplementation; + provides exported.Service + with impl.ServiceImplementation, impl.ServiceImplementation; } diff --git a/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFound/PackageEmptyOrNotFound.java b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundError/PackageEmptyOrNotFound.java similarity index 92% rename from langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFound/PackageEmptyOrNotFound.java rename to langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundError/PackageEmptyOrNotFound.java index fe43a9f9729..81239a1e1a0 100644 --- a/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFound/PackageEmptyOrNotFound.java +++ b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundError/PackageEmptyOrNotFound.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundError/modulesourcepath/m1x/module-info.java b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundError/modulesourcepath/m1x/module-info.java new file mode 100644 index 00000000000..20803f06fa1 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundError/modulesourcepath/m1x/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module m1x { + exports p1; +} diff --git a/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundWarning/PackageEmptyOrNotFound.java b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundWarning/PackageEmptyOrNotFound.java new file mode 100644 index 00000000000..86d412d2fda --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundWarning/PackageEmptyOrNotFound.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// key: compiler.warn.package.empty.or.not.found diff --git a/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundWarning/modulesourcepath/m1x/module-info.java b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundWarning/modulesourcepath/m1x/module-info.java new file mode 100644 index 00000000000..13b74977607 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/PackageEmptyOrNotFoundWarning/modulesourcepath/m1x/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +module m1x { + opens p1; +} diff --git a/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/RepeatedProvides.java b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/RepeatedProvides.java new file mode 100644 index 00000000000..3f4528f77bf --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/RepeatedProvides.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +//key: compiler.err.repeated.provides.for.service + diff --git a/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/module-info.java b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/module-info.java new file mode 100644 index 00000000000..6fcdba52db2 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/module-info.java @@ -0,0 +1,6 @@ +module m { + uses p.I; + provides p.I with p.A; + provides p.I with p.B; +} + diff --git a/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/A.java b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/A.java new file mode 100644 index 00000000000..b5f9f8447bf --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/A.java @@ -0,0 +1,3 @@ +package p; +public class A implements I { } + diff --git a/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/B.java b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/B.java new file mode 100644 index 00000000000..57581c3ae92 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/B.java @@ -0,0 +1,3 @@ +package p; +public class B implements I { } + diff --git a/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/I.java b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/I.java new file mode 100644 index 00000000000..475ca47ebde --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/RepeatedProvidesForService/modulesourcepath/m/p/I.java @@ -0,0 +1,3 @@ +package p; +public interface I { } + diff --git a/langtools/test/tools/javac/diags/examples/UnexpectedTokenInModuleInfo/module-info.java b/langtools/test/tools/javac/diags/examples/UnexpectedTokenInModuleInfo/module-info.java new file mode 100644 index 00000000000..36d3dbc2bd8 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/UnexpectedTokenInModuleInfo/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +// key: compiler.err.expected.module.or.open + +weak module m {} \ No newline at end of file diff --git a/langtools/test/tools/javac/file/LimitedImage.java b/langtools/test/tools/javac/file/LimitedImage.java index 44bc82e8964..0e0ba53855a 100644 --- a/langtools/test/tools/javac/file/LimitedImage.java +++ b/langtools/test/tools/javac/file/LimitedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,6 +74,7 @@ public class LimitedImage { ); //check proper diagnostics when zip/jar FS not present: + System.err.println("Test " + testJar + " on classpath"); actualOutput = new JavacTask(tb, Mode.CMDLINE) .classpath(testJar) .options("-XDrawDiagnostics") @@ -84,9 +85,10 @@ public class LimitedImage { .getOutputLines(OutputKind.DIRECT); if (!expectedOutput.equals(actualOutput)) { - throw new AssertionError("Unexpected output: " + actualOutput); + throw new AssertionError("Unexpected output"); } + System.err.println("Test " + testJar + " on sourcepath"); actualOutput = new JavacTask(tb, Mode.CMDLINE) .sourcepath(testJar) .options("-XDrawDiagnostics") @@ -97,9 +99,10 @@ public class LimitedImage { .getOutputLines(OutputKind.DIRECT); if (!expectedOutput.equals(actualOutput)) { - throw new AssertionError("Unexpected output: " + actualOutput); + throw new AssertionError("Unexpected output"); } + System.err.println("Test " + testJar + " on modulepath"); actualOutput = new JavacTask(tb, Mode.CMDLINE) .options("-XDrawDiagnostics", "--module-path", testJar.toString()) @@ -110,7 +113,7 @@ public class LimitedImage { .getOutputLines(OutputKind.DIRECT); if (!expectedOutput.equals(actualOutput)) { - throw new AssertionError("Unexpected output: " + actualOutput); + throw new AssertionError("Unexpected output"); } expectedOutput = Arrays.asList( @@ -118,6 +121,7 @@ public class LimitedImage { "1 error" ); + System.err.println("Test directory containing " + testJar + " on modulepath"); actualOutput = new JavacTask(tb, Mode.CMDLINE) .classpath() .options("-XDrawDiagnostics", @@ -129,7 +133,7 @@ public class LimitedImage { .getOutputLines(OutputKind.DIRECT); if (!expectedOutput.equals(actualOutput)) { - throw new AssertionError("Unexpected output: " + actualOutput); + throw new AssertionError("Unexpected output"); } } diff --git a/langtools/test/tools/javac/lambda/MethodReferenceNoThisTest.java b/langtools/test/tools/javac/lambda/MethodReferenceNoThisTest.java new file mode 100644 index 00000000000..e0a500e9932 --- /dev/null +++ b/langtools/test/tools/javac/lambda/MethodReferenceNoThisTest.java @@ -0,0 +1,31 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8173456 + * @summary com.sun.tools.javac.util.Assert.error during code compilation + * @compile/fail/ref=MethodReferenceNoThisTest.out -XDrawDiagnostics MethodReferenceNoThisTest.java + */ + +import java.util.function.Function; + +abstract class MethodReferenceNoThisTest_Base { + protected MethodReferenceNoThisTest_Base(Function x) {} +} + +abstract class MethodReferenceNoThisTest_AV { + MethodReferenceNoThisTest_AV(MethodReferenceNoThisTest_Base b) { + } +} + +public class MethodReferenceNoThisTest extends MethodReferenceNoThisTest_Base { + + public MethodReferenceNoThisTest() { + super(V::new); + } + + private class V extends MethodReferenceNoThisTest_AV { + + V(MethodReferenceNoThisTest_Base b) { + super(b); + } + } +} \ No newline at end of file diff --git a/langtools/test/tools/javac/lambda/MethodReferenceNoThisTest.out b/langtools/test/tools/javac/lambda/MethodReferenceNoThisTest.out new file mode 100644 index 00000000000..2dff751f68d --- /dev/null +++ b/langtools/test/tools/javac/lambda/MethodReferenceNoThisTest.out @@ -0,0 +1,2 @@ +MethodReferenceNoThisTest.java:22:15: compiler.err.cant.ref.before.ctor.called: this +1 error \ No newline at end of file diff --git a/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java b/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java index 5efd1e20b22..47eb386b164 100644 --- a/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java +++ b/langtools/test/tools/javac/lambda/intersection/IntersectionTargetTypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * 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,7 +26,6 @@ * @bug 8002099 8010822 * @summary Add support for intersection types in cast expression * @modules jdk.compiler/com.sun.tools.javac.util - * @run main/othervm IntersectionTargetTypeTest */ import com.sun.source.util.JavacTask; diff --git a/langtools/test/tools/javac/modules/AddLimitMods.java b/langtools/test/tools/javac/modules/AddLimitMods.java index 9d7a2e541b4..8c980bb8f86 100644 --- a/langtools/test/tools/javac/modules/AddLimitMods.java +++ b/langtools/test/tools/javac/modules/AddLimitMods.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -217,10 +217,10 @@ public class AddLimitMods extends ModuleTestBase { private static final List> variants = Arrays.asList( new SimpleEntry(new String[] {}, - "Test.java:2:7: compiler.err.package.not.visible: javax.annotation, (compiler.misc.not.def.access.does.not.read.from.unnamed: javax.annotation, java.annotations.common)\n" + "Test.java:2:7: compiler.err.package.not.visible: javax.annotation, (compiler.misc.not.def.access.does.not.read.from.unnamed: javax.annotation, java.xml.ws.annotation)\n" + "Test.java:5:14: compiler.err.package.not.visible: javax.xml.bind, (compiler.misc.not.def.access.does.not.read.from.unnamed: javax.xml.bind, java.xml.bind)\n" + "2 errors\n"), - new SimpleEntry(new String[] {"--add-modules", "java.annotations.common,java.xml.bind"}, + new SimpleEntry(new String[] {"--add-modules", "java.xml.ws.annotation,java.xml.bind"}, null), new SimpleEntry(new String[] {"--limit-modules", "java.xml.ws,jdk.compiler"}, null), diff --git a/langtools/test/tools/javac/modules/AnnotationProcessing.java b/langtools/test/tools/javac/modules/AnnotationProcessing.java index 23066df7f25..80a3eb8da83 100644 --- a/langtools/test/tools/javac/modules/AnnotationProcessing.java +++ b/langtools/test/tools/javac/modules/AnnotationProcessing.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8133884 8162711 8133896 8172158 8172262 + * @bug 8133884 8162711 8133896 8172158 8172262 8173636 * @summary Verify that annotation processing works. * @library /tools/lib * @modules @@ -173,7 +173,7 @@ public class AnnotationProcessing extends ModuleTestBase { String[] module2Packages = moduleDef.split("=>"); module2ExpectedEnclosedElements.put(module2Packages[0], - Arrays.asList(module2Packages[1].split(":"))); + List.of(module2Packages[1].split(":"))); } } @@ -359,7 +359,7 @@ public class AnnotationProcessing extends ModuleTestBase { .writeAll() .getOutput(Task.OutputKind.DIRECT); - List expected = Arrays.asList("Note: field: m1x"); + List expected = List.of("Note: field: m1x"); for (Mode mode : new Mode[] {Mode.API, Mode.CMDLINE}) { List log = new JavacTask(tb, mode) @@ -424,7 +424,7 @@ public class AnnotationProcessing extends ModuleTestBase { .writeAll() .getOutputLines(Task.OutputKind.STDERR); - assertEquals(Arrays.asList("module: m1x"), log); + assertEquals(List.of("module: m1x"), log); } @SupportedAnnotationTypes("*") @@ -472,8 +472,8 @@ public class AnnotationProcessing extends ModuleTestBase { .writeAll() .getOutputLines(Task.OutputKind.DIRECT); - List expectedLog = Arrays.asList("Note: AP Invoked", - "Note: AP Invoked"); + List expectedLog = List.of("Note: AP Invoked", + "Note: AP Invoked"); assertEquals(expectedLog, log); @@ -600,7 +600,7 @@ public class AnnotationProcessing extends ModuleTestBase { JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); try (StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null)) { - List options = Arrays.asList("-d", scratchClasses.toString()); + List options = List.of("-d", scratchClasses.toString()); Iterable files = fm.getJavaFileObjects(scratchSrc); CompilationTask task = comp.getTask(null, fm, null, options, null, files); @@ -939,7 +939,7 @@ public class AnnotationProcessing extends ModuleTestBase { .writeAll() .getOutputLines(OutputKind.STDERR); - expected = Arrays.asList(""); + expected = List.of(""); if (!expected.equals(log)) { throw new AssertionError("Output does not match; output: " + log); @@ -954,15 +954,17 @@ public class AnnotationProcessing extends ModuleTestBase { .writeAll() .getOutputLines(OutputKind.STDERR); - expected = Arrays.asList("SelectAnnotationBTestAP", - "SelectAnnotationBTestAP"); + expected = List.of("SelectAnnotationBTestAP", + "SelectAnnotationBTestAP"); if (!expected.equals(log)) { throw new AssertionError("Output does not match; output: " + log); } log = new JavacTask(tb) - .options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(), + .options("-processor", SelectAnnotationATestAP.class.getName() + "," + + SelectAnnotationBTestAP.class.getName() + "," + + SelectAnnotationAStrictTestAP.class.getName(), "--module-source-path", src.toString(), "-m", "m4x") .outdir(classes) @@ -970,10 +972,43 @@ public class AnnotationProcessing extends ModuleTestBase { .writeAll() .getOutputLines(OutputKind.STDERR); - expected = Arrays.asList("SelectAnnotationATestAP", - "SelectAnnotationBTestAP", - "SelectAnnotationATestAP", - "SelectAnnotationBTestAP"); + expected = List.of("SelectAnnotationATestAP", + "SelectAnnotationBTestAP", + "SelectAnnotationAStrictTestAP", + "SelectAnnotationATestAP", + "SelectAnnotationBTestAP", + "SelectAnnotationAStrictTestAP"); + + if (!expected.equals(log)) { + throw new AssertionError("Output does not match; output: " + log); + } + } + + @Test + public void testDisambiguateAnnotationsUnnamedModule(Path base) throws Exception { + Path classes = base.resolve("classes"); + + Files.createDirectories(classes); + + Path src = base.resolve("src"); + + tb.writeJavaFiles(src, + "package api; public @interface A {}", + "package api; public @interface B {}", + "package impl; import api.*; @A @B public class T {}"); + + List log = new JavacTask(tb) + .options("-processor", SelectAnnotationATestAP.class.getName() + "," + + SelectAnnotationBTestAP.class.getName() + "," + + SelectAnnotationAStrictTestAP.class.getName()) + .outdir(classes) + .files(findJavaFiles(src)) + .run() + .writeAll() + .getOutputLines(OutputKind.STDERR); + + List expected = List.of("SelectAnnotationBTestAP", + "SelectAnnotationBTestAP"); if (!expected.equals(log)) { throw new AssertionError("Output does not match; output: " + log); @@ -994,7 +1029,9 @@ public class AnnotationProcessing extends ModuleTestBase { "package impl; import api.*; @A @B public class T {}"); List log = new JavacTask(tb) - .options("-processor", SelectAnnotationATestAP.class.getName() + "," + SelectAnnotationBTestAP.class.getName(), + .options("-processor", SelectAnnotationATestAP.class.getName() + "," + + SelectAnnotationBTestAP.class.getName() + "," + + SelectAnnotationAStrictTestAP.class.getName(), "-source", "8", "-target", "8") .outdir(classes) .files(findJavaFiles(src)) @@ -1002,10 +1039,10 @@ public class AnnotationProcessing extends ModuleTestBase { .writeAll() .getOutputLines(OutputKind.STDERR); - List expected = Arrays.asList("SelectAnnotationATestAP", - "SelectAnnotationBTestAP", - "SelectAnnotationATestAP", - "SelectAnnotationBTestAP"); + List expected = List.of("SelectAnnotationATestAP", + "SelectAnnotationBTestAP", + "SelectAnnotationATestAP", + "SelectAnnotationBTestAP"); if (!expected.equals(log)) { throw new AssertionError("Output does not match; output: " + log); @@ -1036,6 +1073,22 @@ public class AnnotationProcessing extends ModuleTestBase { } + public static final class SelectAnnotationAStrictTestAP extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + System.err.println("SelectAnnotationAStrictTestAP"); + + return false; + } + + @Override + public Set getSupportedAnnotationTypes() { + return Set.of("m2x/api.A"); + } + + } + private static void writeFile(String content, Path base, String... pathElements) throws IOException { Path file = resolveFile(base, pathElements); diff --git a/langtools/test/tools/javac/modules/MissingModuleTest.java b/langtools/test/tools/javac/modules/MissingModuleTest.java new file mode 100644 index 00000000000..76c5f2a0bf2 --- /dev/null +++ b/langtools/test/tools/javac/modules/MissingModuleTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8172240 + * @summary javac should not need the transitive closure to compile a module + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.code + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.processing + * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase + * @run main MissingModuleTest + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.Task.Expect; + +public class MissingModuleTest extends ModuleTestBase { + + public static void main(String... args) throws Exception { + new MissingModuleTest().runTests(); + } + + @Test + public void testMissingNotNeeded(Path base) throws Exception { + doTest(base, "m1x", new String[0]); + } + + @Test + public void testMissingNeededTransitive(Path base) throws Exception { + doTest(base, "m2x", "- compiler.err.module.not.found: m2x", "1 error"); + } + + @Test + public void testMissingNeededDirect(Path base) throws Exception { + doTest(base, "m3x", "module-info.java:1:24: compiler.err.module.not.found: m3x", "1 error"); + } + + @Test + public void testMultipleErrors(Path base) throws Exception { + doTest(base, "m4x", "module-info.java:1:38: compiler.err.module.not.found: m4x", "1 error"); + } + + private void doTest(Path base, String toDelete, String... errors) throws Exception { + //note: avoiding use of java.base, as that gets special handling on some places: + Path srcMP = base.resolve("src-mp"); + Path m1x = srcMP.resolve("m1x"); + tb.writeJavaFiles(m1x, + "module m1x { exports api1; }", + "package api1; public interface Api { }"); + Path m2x = srcMP.resolve("m2x"); + tb.writeJavaFiles(m2x, + "module m2x { requires m1x; exports api2; }", + "package api2; public interface Api { }"); + Path m3x = srcMP.resolve("m3x"); + tb.writeJavaFiles(m3x, + "module m3x { requires transitive m2x; }"); + Path m4x = srcMP.resolve("m4x"); + tb.writeJavaFiles(m4x, + "module m4x { requires transitive m2x; }"); + Path m5x = srcMP.resolve("m5x"); + tb.writeJavaFiles(m5x, + "module m5x { requires transitive m4x; }"); + Path classesMP = base.resolve("classes-mp"); + tb.createDirectories(classesMP); + + new JavacTask(tb) + .options("--module-source-path", srcMP.toString()) + .outdir(classesMP) + .files(findJavaFiles(srcMP)) + .run() + .writeAll(); + + tb.cleanDirectory(classesMP.resolve(toDelete)); + Files.delete(classesMP.resolve(toDelete)); + + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "module test { requires m3x; requires m4x; requires m5x; } "); + Path classes = base.resolve("classes"); + tb.createDirectories(classes); + + List log = new JavacTask(tb) + .options("--module-path", classesMP.toString(), + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(src)) + .run(errors.length > 0 ? Expect.FAIL : Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + if (errors.length == 0) { + errors = new String[] {""}; + } + + if (!log.equals(Arrays.asList(errors))) + throw new Exception("expected output not found: " + log); + } + +} diff --git a/langtools/test/tools/javac/modules/ModulesAndModuleSourcePathTest.java b/langtools/test/tools/javac/modules/ModulesAndModuleSourcePathTest.java index 6b54a74f5cf..1edc21de22a 100644 --- a/langtools/test/tools/javac/modules/ModulesAndModuleSourcePathTest.java +++ b/langtools/test/tools/javac/modules/ModulesAndModuleSourcePathTest.java @@ -22,7 +22,8 @@ */ /** - * @test 8165102 + * @test + * @bug 8165102 * @summary incorrect message from javac * @library /tools/lib * @modules diff --git a/langtools/test/tools/javac/modules/ProvidesTest.java b/langtools/test/tools/javac/modules/ProvidesTest.java index 68ffe57d8cc..0e92bb96934 100644 --- a/langtools/test/tools/javac/modules/ProvidesTest.java +++ b/langtools/test/tools/javac/modules/ProvidesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /** * @test * @summary simple tests of module provides - * @bug 8168854 + * @bug 8168854 8172807 * @library /tools/lib * @modules * jdk.compiler/com.sun.tools.javac.api @@ -109,21 +109,56 @@ public class ProvidesTest extends ModuleTestBase { } @Test - public void testDuplicateProvides(Path base) throws Exception { + public void testDuplicateImplementations1(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, - "module m { provides p1.C1 with p2.C2; provides p1.C1 with p2.C2; }", + "module m { exports p1; exports p2; provides p1.C1 with p2.C2, p2.C2; }", "package p1; public class C1 { }", "package p2; public class C2 extends p1.C1 { }"); Path classes = base.resolve("classes"); Files.createDirectories(classes); - new JavacTask(tb) - .options("-XDrawDiagnostic") + List output = new JavacTask(tb) + .options("-XDrawDiagnostics") .outdir(classes) .files(findJavaFiles(src)) .run(Task.Expect.FAIL) - .writeAll(); + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList( + "module-info.java:1:65: compiler.err.duplicate.provides: p1.C1, p2.C2", + "1 error"); + if (!output.containsAll(expected)) { + throw new Exception("Expected output not found"); + } + } + + @Test + public void testDuplicateImplementations2(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "module m { exports p1; provides p1.C1 with p2.C2; provides p1.C1 with p2.C2; }", + "package p1; public class C1 { }", + "package p2; public class C2 extends p1.C1 { }"); + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + + List output = new JavacTask(tb) + .options("-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList( + "module-info.java:1:62: compiler.err.repeated.provides.for.service: p1.C1", + "module-info.java:1:73: compiler.err.duplicate.provides: p1.C1, p2.C2", + "2 errors"); + if (!output.containsAll(expected)) { + throw new Exception("Expected output not found"); + } } @Test @@ -228,7 +263,7 @@ public class ProvidesTest extends ModuleTestBase { public void testSeveralImplementations(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, - "module m { provides p.C with p.Impl1; provides p.C with p.Impl2; }", + "module m { provides p.C with p.Impl1, p.Impl2; }", "package p; public class C { }", "package p; public class Impl1 extends p.C { }", "package p; public class Impl2 extends p.C { }"); @@ -240,6 +275,30 @@ public class ProvidesTest extends ModuleTestBase { .writeAll(); } + @Test + public void testRepeatedProvides(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "module m { exports p; provides p.C with p.Impl1; provides p.C with p.Impl2; }", + "package p; public class C { }", + "package p; public class Impl1 extends p.C { }", + "package p; public class Impl2 extends p.C { }"); + + List output = new JavacTask(tb) + .options("-XDrawDiagnostics") + .outdir(Files.createDirectories(base.resolve("classes"))) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList("module-info.java:1:60: compiler.err.repeated.provides.for.service: p.C", + "1 error"); + if (!output.containsAll(expected)) { + throw new Exception("Expected output not found"); + } + } + @Test public void testOneImplementationsForServices(Path base) throws Exception { Path src = base.resolve("src"); diff --git a/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java b/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java index 8d76c9ec473..bef138441fc 100644 --- a/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java +++ b/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,7 +105,7 @@ public class ReportNonExistentPackageTest extends ModuleTestBase { } @Test - public void testExportPrivateEmptyPackage(Path base) throws Exception { + public void testOpensEmptyPackage(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { opens p; }"); @@ -116,15 +116,34 @@ public class ReportNonExistentPackageTest extends ModuleTestBase { .options("-XDrawDiagnostics") .outdir(classes) .files(findJavaFiles(src)) - .run(Task.Expect.FAIL) + .run(Task.Expect.SUCCESS) .writeAll() .getOutput(Task.OutputKind.DIRECT); - if (!log.contains("module-info.java:1:18: compiler.err.package.empty.or.not.found: p")) + if (!log.contains("module-info.java:1:18: compiler.warn.package.empty.or.not.found: p")) throw new Exception("expected output not found, actual output: " + log); } @Test - public void testExportPrivateOnlyWithResources(Path base) throws Exception { + public void testOpensEmptyPackageSuppressed(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + "@SuppressWarnings(\"opens\") module m { opens p; }"); + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + + String log = new JavacTask(tb) + .options("-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll() + .getOutput(Task.OutputKind.DIRECT); + if (!log.equals("")) + throw new Exception("expected output not found, actual output: " + log); + } + + @Test + public void testOpenOnlyWithResources(Path base) throws Exception { Path src = base.resolve("src"); tb.writeJavaFiles(src, "module m { opens p; }"); diff --git a/langtools/test/tools/javac/modules/UnexpectedTokenInModuleInfoTest.java b/langtools/test/tools/javac/modules/UnexpectedTokenInModuleInfoTest.java new file mode 100644 index 00000000000..ea8d098e340 --- /dev/null +++ b/langtools/test/tools/javac/modules/UnexpectedTokenInModuleInfoTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * 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 8166420 + * @summary Confusing error message when reading bad module declaration + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase + * @run main UnexpectedTokenInModuleInfoTest + */ + +import java.nio.file.*; +import java.util.List; +import java.util.Arrays; + +import toolbox.JavacTask; +import toolbox.Task; + +public class UnexpectedTokenInModuleInfoTest extends ModuleTestBase { + public static void main(String... args) throws Exception { + UnexpectedTokenInModuleInfoTest t = new UnexpectedTokenInModuleInfoTest(); + t.runTests(); + } + + @Test + public void testSingleModule(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeFile(src.resolve("module-info.java"), "weak module m { }"); + + List output = new JavacTask(tb) + .options("-XDrawDiagnostics") + .files(src.resolve("module-info.java")) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expected = Arrays.asList("module-info.java:1:1: compiler.err.expected.module.or.open", + "1 error"); + if (!output.containsAll(expected)) { + throw new Exception("Expected output not found"); + } + } +} \ No newline at end of file diff --git a/langtools/test/tools/javac/parser/extend/TrialParserFactory.java b/langtools/test/tools/javac/parser/extend/TrialParserFactory.java index 39ff06c4a8b..6ac4c60d279 100644 --- a/langtools/test/tools/javac/parser/extend/TrialParserFactory.java +++ b/langtools/test/tools/javac/parser/extend/TrialParserFactory.java @@ -52,4 +52,9 @@ class TrialParserFactory extends ParserFactory { com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments); return new TrialParser(this, lexer, keepDocComments, keepLineMap, keepEndPos); } + + @Override + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { + return newParser(input, keepDocComments, keepEndPos, keepLineMap); + } } diff --git a/langtools/test/tools/javac/processing/messager/6362067/T6362067.out b/langtools/test/tools/javac/processing/messager/6362067/T6362067.out index 20de3ea84ec..af32147b3a1 100644 --- a/langtools/test/tools/javac/processing/messager/6362067/T6362067.out +++ b/langtools/test/tools/javac/processing/messager/6362067/T6362067.out @@ -1,5 +1,5 @@ T6362067.java:19:8: compiler.note.proc.messager: note:elem T6362067.java:17:1: compiler.note.proc.messager: note:anno T6362067.java:18:1: compiler.note.proc.messager: note:anno -T6362067.java:18:1: compiler.note.proc.messager: note:value +T6362067.java:18:19: compiler.note.proc.messager: note:value - compiler.note.proc.messager: note:nopos diff --git a/langtools/test/tools/javac/processing/messager/6388543/T6388543.java b/langtools/test/tools/javac/processing/messager/6388543/T6388543.java new file mode 100644 index 00000000000..c5b09ffb3e5 --- /dev/null +++ b/langtools/test/tools/javac/processing/messager/6388543/T6388543.java @@ -0,0 +1,101 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6388543 + * @summary improve accuracy of source positions for AnnotationValue param of Messager.printMessage + * @library /tools/javac/lib + * @modules jdk.compiler + * @build JavacTestingAbstractProcessor T6388543 + * @compile/ref=T6388543.out -XDrawDiagnostics -processor T6388543 -proc:only T6388543.java + */ + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Set; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; + +import static javax.tools.Diagnostic.Kind.NOTE; + +class Annotated { + @A(1) + int a1; + + @A(value = 2) + int a2; + + @A(value = {3}) + int a3; + + @A(value = {4, 5}) + int a4; + + @B(x = @C(x = E.ONE, y = E.TWO), y = @C(x = E.ONE, y = E.TWO)) + int b; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface A { + int[] value() default 0; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface B { + C x() default @C; + + C y() default @C; +} + +@Retention(RetentionPolicy.RUNTIME) +@interface C { + E x() default E.ONE; + + E y() default E.ONE; +} + +enum E { + ONE, + TWO +} + +public class T6388543 extends JavacTestingAbstractProcessor { + public boolean process(Set annos, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + return false; + } + for (Element e : elements.getTypeElement("Annotated").getEnclosedElements()) { + for (AnnotationMirror a : e.getAnnotationMirrors()) { + for (AnnotationValue v : a.getElementValues().values()) { + printValue(e, a, v); + } + } + } + return false; + } + + private void printValue(Element e, AnnotationMirror a, AnnotationValue v) { + messager.printMessage(NOTE, String.format("note:value %s + %s", a, v), e, a, v); + v.accept( + new SimpleAnnotationValueVisitor() { + @Override + public Void visitArray(List values, Void unused) { + for (AnnotationValue value : values) { + printValue(e, a, value); + } + return null; + } + + @Override + public Void visitAnnotation(AnnotationMirror nestedAnnotation, Void unused) { + for (AnnotationValue value : nestedAnnotation.getElementValues().values()) { + printValue(e, a, value); + } + return null; + } + }, + null); + } +} diff --git a/langtools/test/tools/javac/processing/messager/6388543/T6388543.out b/langtools/test/tools/javac/processing/messager/6388543/T6388543.out new file mode 100644 index 00000000000..1342a170562 --- /dev/null +++ b/langtools/test/tools/javac/processing/messager/6388543/T6388543.out @@ -0,0 +1,15 @@ +T6388543.java:24:8: compiler.note.proc.messager: note:value @A({1}) + {1} +T6388543.java:24:8: compiler.note.proc.messager: note:value @A({1}) + 1 +T6388543.java:27:16: compiler.note.proc.messager: note:value @A({2}) + {2} +T6388543.java:27:16: compiler.note.proc.messager: note:value @A({2}) + 2 +T6388543.java:30:16: compiler.note.proc.messager: note:value @A({3}) + {3} +T6388543.java:30:17: compiler.note.proc.messager: note:value @A({3}) + 3 +T6388543.java:33:16: compiler.note.proc.messager: note:value @A({4, 5}) + {4, 5} +T6388543.java:33:17: compiler.note.proc.messager: note:value @A({4, 5}) + 4 +T6388543.java:33:20: compiler.note.proc.messager: note:value @A({4, 5}) + 5 +T6388543.java:36:12: compiler.note.proc.messager: note:value @B(x=@C(x=E.ONE, y=E.TWO), y=@C(x=E.ONE, y=E.TWO)) + @C(x=E.ONE, y=E.TWO) +T6388543.java:36:20: compiler.note.proc.messager: note:value @B(x=@C(x=E.ONE, y=E.TWO), y=@C(x=E.ONE, y=E.TWO)) + E.ONE +T6388543.java:36:31: compiler.note.proc.messager: note:value @B(x=@C(x=E.ONE, y=E.TWO), y=@C(x=E.ONE, y=E.TWO)) + E.TWO +T6388543.java:36:42: compiler.note.proc.messager: note:value @B(x=@C(x=E.ONE, y=E.TWO), y=@C(x=E.ONE, y=E.TWO)) + @C(x=E.ONE, y=E.TWO) +T6388543.java:36:50: compiler.note.proc.messager: note:value @B(x=@C(x=E.ONE, y=E.TWO), y=@C(x=E.ONE, y=E.TWO)) + E.ONE +T6388543.java:36:61: compiler.note.proc.messager: note:value @B(x=@C(x=E.ONE, y=E.TWO), y=@C(x=E.ONE, y=E.TWO)) + E.TWO diff --git a/langtools/test/tools/javac/processing/model/element/TestPackageElement.java b/langtools/test/tools/javac/processing/model/element/TestPackageElement.java index 1d0d8b58a94..1d6803c5565 100644 --- a/langtools/test/tools/javac/processing/model/element/TestPackageElement.java +++ b/langtools/test/tools/javac/processing/model/element/TestPackageElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. * 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,16 +23,18 @@ /* * @test - * @bug 6449798 6399404 + * @bug 6449798 6399404 8173776 * @summary Test basic workings of PackageElement * @author Joseph D. Darcy * @library /tools/javac/lib * @modules java.compiler * jdk.compiler * @build JavacTestingAbstractProcessor TestPackageElement - * @compile -processor TestPackageElement -proc:only TestPackageElement.java + * @compile -processor TestPackageElement -proc:only TestPackageElement.java + * @compile -processor TestPackageElement -proc:only --release 8 TestPackageElement.java */ +import java.util.Objects; import java.util.Set; import javax.annotation.processing.*; import javax.lang.model.SourceVersion; @@ -67,7 +69,22 @@ public class TestPackageElement extends JavacTestingAbstractProcessor { PackageElement javaLang = eltUtils.getPackageElement("java.lang"); if (javaLang.isUnnamed()) throw new RuntimeException("Package java.lang is unnamed!"); + + testEnclosingElement(javaLang); } return true; } + + void testEnclosingElement(PackageElement javaLang) { + SourceVersion version = processingEnv.getSourceVersion(); + Element enclosing = javaLang.getEnclosingElement(); + Element expectedEnclosing = + (version.compareTo(RELEASE_9) < 0) ? // No modules + null : + eltUtils.getModuleElement("java.base"); + + if (!Objects.equals(enclosing, expectedEnclosing)) + throw new RuntimeException("Unexpected enclosing element under source version " + + version); + } } diff --git a/langtools/test/tools/javac/processing/model/util/printing/module-info.java b/langtools/test/tools/javac/processing/model/util/printing/module-info.java new file mode 100644 index 00000000000..814a6d6b062 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/util/printing/module-info.java @@ -0,0 +1,18 @@ +/* + * @test + * @bug 8173609 + * @summary printing of modules + * @compile/ref=module-info.out -Xprint p/P.java module-info.java + */ + +/** + * Printing of modules + */ +@Deprecated +module printing { + requires static transitive java.base; + exports p to m.m1, m.m2; + opens p to m.m1, m.m2; + uses p.P; + provides p.P with p.P.P1, p.P.P2; +} diff --git a/langtools/test/tools/javac/processing/model/util/printing/module-info.out b/langtools/test/tools/javac/processing/model/util/printing/module-info.out new file mode 100644 index 00000000000..32d8ee3d0a3 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/util/printing/module-info.out @@ -0,0 +1,27 @@ +package p; + +public class P { + + public static class P1 extends p.P { + + public P1(); + } + + public static class P2 extends p.P { + + public P2(); + } + + public P(); +} +/** + * Printing of modules + */ +@java.lang.Deprecated +module printing { + requires static transitive java.base; + exports p to m.m1, m.m2; + opens p to m.m1, m.m2; + uses p.P; + provides p.P with p.P.P1, p.P.P2; +} diff --git a/langtools/test/tools/javac/processing/model/util/printing/p/P.java b/langtools/test/tools/javac/processing/model/util/printing/p/P.java new file mode 100644 index 00000000000..17fd889c4b8 --- /dev/null +++ b/langtools/test/tools/javac/processing/model/util/printing/p/P.java @@ -0,0 +1,6 @@ +package p; + +public class P { + public static class P1 extends P {} + public static class P2 extends P {} +} diff --git a/langtools/test/tools/javac/tree/JavacTreeScannerTest.java b/langtools/test/tools/javac/tree/JavacTreeScannerTest.java index 24519b4cd83..b111d18ba86 100644 --- a/langtools/test/tools/javac/tree/JavacTreeScannerTest.java +++ b/langtools/test/tools/javac/tree/JavacTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest JavacTreeScannerTest - * @run main/othervm JavacTreeScannerTest -q -r . + * @run main JavacTreeScannerTest -q -r . */ import java.io.*; diff --git a/langtools/test/tools/javac/tree/SourceTreeScannerTest.java b/langtools/test/tools/javac/tree/SourceTreeScannerTest.java index dd16b5afdc0..c272425cc25 100644 --- a/langtools/test/tools/javac/tree/SourceTreeScannerTest.java +++ b/langtools/test/tools/javac/tree/SourceTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util * @build AbstractTreeScannerTest SourceTreeScannerTest - * @run main/othervm SourceTreeScannerTest -q -r . + * @run main SourceTreeScannerTest -q -r . */ import java.io.*; diff --git a/langtools/test/tools/javac/tree/TreePosTest.java b/langtools/test/tools/javac/tree/TreePosTest.java index 99ffbc31105..835531fd669 100644 --- a/langtools/test/tools/javac/tree/TreePosTest.java +++ b/langtools/test/tools/javac/tree/TreePosTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,7 +108,7 @@ import static com.sun.tools.javac.util.Position.NOPOS; * jdk.compiler/com.sun.tools.javac.file * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @run main/othervm TreePosTest -q -r . + * @run main TreePosTest -q -r . */ public class TreePosTest { /** diff --git a/langtools/test/tools/javac/varargs/7043922/T7043922.java b/langtools/test/tools/javac/varargs/7043922/T7043922.java index 44da1af89a0..b9624d027a3 100644 --- a/langtools/test/tools/javac/varargs/7043922/T7043922.java +++ b/langtools/test/tools/javac/varargs/7043922/T7043922.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file * jdk.compiler/com.sun.tools.javac.util - * @run main/othervm T7043922 */ import com.sun.source.util.JavacTask; diff --git a/langtools/test/tools/jdeps/modules/SplitPackage.java b/langtools/test/tools/jdeps/modules/SplitPackage.java index 844c96d4d40..5764a666775 100644 --- a/langtools/test/tools/jdeps/modules/SplitPackage.java +++ b/langtools/test/tools/jdeps/modules/SplitPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ public class SplitPackage { private static final Path CLASSES_DIR = Paths.get("classes"); private static final String SPLIT_PKG_NAME = "javax.annotation"; - private static final String JAVA_ANNOTATIONS_COMMON = "java.annotations.common"; + private static final String JAVA_XML_WS_ANNOTATION = "java.xml.ws.annotation"; /** * Compiles classes used by the test */ @@ -64,7 +64,7 @@ public class SplitPackage { @Test public void runTest() throws Exception { // split package detected if java.annotation.common is in the root set - runTest(JAVA_ANNOTATIONS_COMMON, SPLIT_PKG_NAME); + runTest(JAVA_XML_WS_ANNOTATION, SPLIT_PKG_NAME); runTest("ALL-SYSTEM", SPLIT_PKG_NAME); // default runTest(null, SPLIT_PKG_NAME); @@ -98,7 +98,7 @@ public class SplitPackage { throw new RuntimeException(splitPackages.toString()); } - // java.annotations.common is not observable + // java.xml.ws.annotation is not observable DepsAnalyzer analyzer = jdeps.getDepsAnalyzer(); assertTrue(analyzer.run()); diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index c794b30b714..0b54c856da4 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -247,6 +247,10 @@ java.management_ADD_JAVAC_FLAGS := -Xdoclint:all/protected,-reference '-Xdoclint ################################################################################ +java.management.rmi_ADD_JAVAC_FLAGS := -Xdoclint:all/protected,-reference '-Xdoclint/package:javax.*' + +################################################################################ + java.prefs_ADD_JAVAC_FLAGS := -Xdoclint:all/protected '-Xdoclint/package:java.*,javax.*' ################################################################################ @@ -450,7 +454,7 @@ jdk.dev_COPY := .js oqlhelp.html .txt ################################################################################ -jdk.jvmstat_COPY := aliasmap +jdk.internal.jvmstat_COPY := aliasmap ################################################################################ diff --git a/make/Images.gmk b/make/Images.gmk index 815168af063..09740cb53d9 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -72,6 +72,7 @@ JRE_COMPACT3_MODULES := \ java.compiler \ java.instrument \ java.management \ + java.management.rmi \ java.naming \ java.prefs \ java.security.jgss \ diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 49f301d9da8..4ceb4513623 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -51,6 +51,7 @@ BOOT_MODULES += \ java.instrument \ java.logging \ java.management \ + java.management.rmi \ java.naming \ java.prefs \ java.rmi \ @@ -58,6 +59,7 @@ BOOT_MODULES += \ java.xml \ jdk.httpserver \ jdk.management \ + jdk.management.agent \ jdk.net \ jdk.sctp \ jdk.unsupported \ @@ -71,11 +73,11 @@ BOOT_MODULES += \ UPGRADEABLE_MODULES += \ java.activation \ - java.annotations.common \ java.corba \ java.transaction \ java.xml.bind \ java.xml.ws \ + java.xml.ws.annotation \ # # Modules explicitly declared as not being upgradeable even though they require diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 4b0ce04f1c6..ae0cc2068de 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -685,7 +685,7 @@ define SetupNativeCompilationBody $$($1_OBJECT_DIR)/$$($1_NOSUFFIX).comp.vardeps) ifneq ($$($1_PRECOMPILED_HEADER), ) - ifeq ($(USE_PRECOMPILED_HEADER), 1) + ifeq ($(USE_PRECOMPILED_HEADER), true) ifeq ($(TOOLCHAIN_TYPE), microsoft) $1_PCH_FILE := $$($1_OBJECT_DIR)/$1.pch $1_GENERATED_PCH_SRC := $$($1_OBJECT_DIR)/$1_pch.cpp diff --git a/nashorn/.hgtags b/nashorn/.hgtags index 9a3afbe84fb..22c28403722 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -388,3 +388,4 @@ ace1d994bca775d6545a4c874ae73d1dfc9ec18b jdk-9+150 ddc52e72757086a75a54371e8e7f56a3f89f1e55 jdk-9+152 19aaaf2d02b7d6986538cd9a8c46901ecb50eebf jdk-9+153 a84b49cfee63716975535abae2865ffef4dd6474 jdk-9+154 +f9bb37a817b3cd3b758a60f3c68258a6554eb382 jdk-9+155 diff --git a/nashorn/make/BuildNashorn.gmk b/nashorn/make/BuildNashorn.gmk index fd11bd6e9db..a0929c415d0 100644 --- a/nashorn/make/BuildNashorn.gmk +++ b/nashorn/make/BuildNashorn.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -36,12 +36,10 @@ include TextFileProcessing.gmk JDK_CLASSES := $(call PathList, $(strip $(addprefix $(JDK_OUTPUTDIR)/modules/, \ java.base java.logging java.scripting jdk.dynalink))) -NASHORN_JAR := $(IMAGES_OUTPUTDIR)/nashorn.jar - MODULESOURCEPATH := $(NASHORN_TOPDIR)/src/*/share/classes # Need to use source and target 8 for nasgen to work. -$(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \ +$(eval $(call SetupJavaCompiler, GENERATE_NEWBYTECODE_DEBUG, \ JVM := $(JAVA_JAVAC), \ JAVAC := $(NEW_JAVAC), \ FLAGS := -g -source 9 -target 9 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \ @@ -53,11 +51,10 @@ $(eval $(call SetupJavaCompiler,GENERATE_NEWBYTECODE_DEBUG, \ # Name the compilation setup the same as the module, as is done in the global # CompileJavaModules.gmk, to make dependency checking with other modules work # seamlessly. -$(eval $(call SetupJavaCompilation,jdk.scripting.nashorn, \ +$(eval $(call SetupJavaCompilation, jdk.scripting.nashorn, \ SETUP := GENERATE_NEWBYTECODE_DEBUG, \ MODULE := jdk.scripting.nashorn, \ SRC := $(NASHORN_TOPDIR)/src/jdk.scripting.nashorn/share/classes, \ - EXCLUDE_FILES := META-INF/MANIFEST.MF, \ COPY := .properties .js, \ BIN := $(SUPPORT_OUTPUTDIR)/special_classes)) @@ -65,7 +62,7 @@ NASGEN_SRC := $(NASHORN_TOPDIR)/buildtools/nasgen/src ASM_SRC := $(JDK_TOPDIR)/src/java.base/share/classes/jdk/internal/org/objectweb/asm # Build nasgen -$(eval $(call SetupJavaCompilation,BUILD_NASGEN, \ +$(eval $(call SetupJavaCompilation, BUILD_NASGEN, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := $(NASGEN_SRC) $(ASM_SRC), \ BIN := $(BUILDTOOLS_OUTPUTDIR)/nasgen_classes)) @@ -107,21 +104,7 @@ $(eval $(call SetupTextFileProcessing, BUILD_VERSION_FILE, \ # Version processing needs to happen after nasgen run since nasgen run deletes it $(BUILD_VERSION_FILE): $(NASGEN_RUN_FILE) - -MANIFEST_ATTRIBUTES := Name: jdk/nashorn/\nImplementation-Title: Oracle Nashorn\nImplementation-Version: $(VERSION_SHORT) - -# Create nashorn.jar from the final classes dir -$(eval $(call SetupJarArchive,BUILD_NASHORN_JAR, \ - DEPENDENCIES := $(NASGEN_RUN_FILE) $(BUILD_VERSION_FILE), \ - SRCS := $(NASHORN_CLASSES_DIR), \ - SUFFIXES := .class .js .properties Factory, \ - MANIFEST := $(NASHORN_TOPDIR)/src/jdk.scripting.nashorn/share/classes/META-INF/MANIFEST.MF, \ - EXTRA_MANIFEST_ATTR := $(MANIFEST_ATTRIBUTES), \ - SKIP_METAINF := true, \ - JAR := $(NASHORN_JAR), \ -)) - -compile: $(NASHORN_RUN_FILE) $(BUILD_VERSION_FILE) -all: $(NASHORN_JAR) +compile: $(NASGEN_RUN_FILE) $(BUILD_VERSION_FILE) +all: compile .PHONY: compile all diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java index 488beb29a81..c55e8c45e4e 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java @@ -77,6 +77,7 @@ final class WeighNodes extends NodeOperatorVisitor { static final long CALL_WEIGHT = 10; static final long CATCH_WEIGHT = 10; static final long COMPARE_WEIGHT = 6; + static final long CONST_WEIGHT = 2; static final long CONTINUE_WEIGHT = 1; static final long IF_WEIGHT = 2; static final long LITERAL_WEIGHT = 10; @@ -185,7 +186,7 @@ final class WeighNodes extends NodeOperatorVisitor { @Override public Node leaveIdentNode(final IdentNode identNode) { - weight += ACCESS_WEIGHT + identNode.getName().length() * 2; + weight += ACCESS_WEIGHT; return identNode; } @@ -210,6 +211,11 @@ final class WeighNodes extends NodeOperatorVisitor { @SuppressWarnings("rawtypes") @Override public boolean enterLiteralNode(final LiteralNode literalNode) { + if (literalNode instanceof LiteralNode.PrimitiveLiteralNode) { + weight += CONST_WEIGHT; + return false; + } + weight += LITERAL_WEIGHT; if (literalNode instanceof ArrayLiteralNode) { diff --git a/nashorn/test/script/basic/JDK-8030182_2.js b/nashorn/test/script/basic/JDK-8030182_2.js index 4c2f5c429f6..4b563deff1e 100644 --- a/nashorn/test/script/basic/JDK-8030182_2.js +++ b/nashorn/test/script/basic/JDK-8030182_2.js @@ -31,7 +31,7 @@ var str = ""; // large code to force splitting -for (i = 0; i < 1000; ++i) +for (i = 0; i < 2000; ++i) str +="o = new Object()\n"; str +="g()"; diff --git a/test/Makefile b/test/Makefile index 49a47fd5230..ecc78ee9110 100644 --- a/test/Makefile +++ b/test/Makefile @@ -60,7 +60,12 @@ all: jdk_all langtools_all jaxp_all -include $(TOPDIR)/closed/test/Makefile ifeq ($(TEST_JOBS), 0) - JDK_TEST_JOBS=$(JOBS) + ifeq ($(shell $(EXPR) $(JOBS) \> 50), 1) + # JTReg cannot handle more than 50 in concurrency + JDK_TEST_JOBS=50 + else + JDK_TEST_JOBS=$(JOBS) + endif else JDK_TEST_JOBS=$(TEST_JOBS) endif diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 06299e7ecd5..8ac981d28b2 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -33,6 +33,8 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; + +import sun.hotspot.cpuinfo.CPUInfo; import sun.hotspot.gc.GC; import sun.hotspot.WhiteBox; @@ -62,6 +64,8 @@ public class VMProps implements Callable> { map.put("vm.simpleArch", vmArch()); map.put("vm.debug", vmDebug()); map.put("vm.jvmci", vmJvmci()); + map.put("vm.emulatedClient", vmEmulatedClient()); + map.put("vm.cpu.features", cpuFeatures()); vmGC(map); // vm.gc.X = true/false VMProps.dump(map); @@ -165,6 +169,24 @@ public class VMProps implements Callable> { return "" + (WB.getBooleanVMFlag("EnableJVMCI") != null); } + /** + * @return true if VM runs in emulated-client mode and false otherwise. + */ + protected String vmEmulatedClient() { + String vmInfo = System.getProperty("java.vm.info"); + if (vmInfo == null) { + return "false"; + } + return "" + vmInfo.contains(" emulated-client"); + } + + /** + * @return supported CPU features + */ + protected String cpuFeatures() { + return CPUInfo.getFeatures().toString(); + } + /** * For all existing GC sets vm.gc.X property. * Example vm.gc.G1=true means: diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index 3f924371c43..26bbf1bae94 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -63,6 +63,10 @@ public class Platform { return vmName.contains("Embedded"); } + public static boolean isEmulatedClient() { + return vmInfo.contains(" emulated-client"); + } + public static boolean isTieredSupported() { return compiler.contains("Tiered Compilers"); }
        All Methods " + + "Instance Methods" + + " " + + "Concrete Methods " + + "